--Pan Zoom Rotate effect filter by khaver obs = obslua SETTING_CX = 'pos_cx' SETTING_CY = 'pos_cy' SETTING_ZOOM = 'zoom' SETTING_ROT = 'rotate' TEXT_CX = 'Pan X' TEXT_CY = 'Pan Y' TEXT_ZOOM = 'Zoom' TEXT_ROT = 'Rotate' -- Returns the description displayed in the Scripts window function script_description() return [[Filter for panning, zooming & rotating]] end function script_load(settings) obs.obs_register_source(source_info) end source_info = {} source_info.id = 'filter-pzr' source_info.type = obs.OBS_SOURCE_TYPE_FILTER source_info.output_flags = obs.OBS_SOURCE_VIDEO source_info.get_name = function() return "Pan-Zoom-Rotate" end source_info.create = function(settings, source) local filter = {} filter.source = source filter.width = 1 filter.height = 1 --set_render_size(filter) obs.obs_enter_graphics() --local effect_path = script_path() .. 'filter-PZR/filter-PZR.effect' --filter.effect = obs.gs_effect_create_from_file(effect_path, nil) filter.effect = obs.gs_effect_create(shader, nil, nil) obs.obs_leave_graphics() if filter.effect == nil then source_info.destroy(filter) return nil end filter.params = {} filter.params.pos_cx = obs.gs_effect_get_param_by_name(filter.effect, 'pos_cx') filter.params.pos_cy = obs.gs_effect_get_param_by_name(filter.effect, 'pos_cy') filter.params.zoom = obs.gs_effect_get_param_by_name(filter.effect, 'zoom') filter.params.rotate = obs.gs_effect_get_param_by_name(filter.effect, 'rotate') filter.params.width = obs.gs_effect_get_param_by_name(filter.effect, 'width') filter.params.height = obs.gs_effect_get_param_by_name(filter.effect, 'height') source_info.update(filter, settings) return filter end source_info.destroy = function(filter) if filter.effect ~= nil then obs.obs_enter_graphics() obs.gs_effect_destroy(filter.effect) filter.effect = nil obs.obs_leave_graphics() end end source_info.get_width = function(filter) return filter.width end source_info.get_height = function(filter) return filter.height end source_info.get_properties = function(settings) props = obs.obs_properties_create() obs.obs_properties_add_float_slider(props, SETTING_CX, TEXT_CX, -1.0, 1.0, 0.001) obs.obs_properties_add_float_slider(props, SETTING_CY, TEXT_CY, -1.0, 1.0, 0.001) obs.obs_properties_add_float_slider(props, SETTING_ZOOM, TEXT_ZOOM, 0.0, 10.0, 0.001) obs.obs_properties_add_float_slider(props, SETTING_ROT, TEXT_ROT, -180.0, 180.0, 0.01) return props end source_info.get_defaults = function(settings) obs.obs_data_set_default_double(settings, SETTING_CX, 0.0) obs.obs_data_set_default_double(settings, SETTING_CY, 0.0) obs.obs_data_set_default_double(settings, SETTING_ZOOM, 1.0) obs.obs_data_set_default_double(settings, SETTING_ROT, 0.0) end source_info.update = function(filter, settings) filter.pos_cx = obs.obs_data_get_double(settings, SETTING_CX) filter.pos_cy = obs.obs_data_get_double(settings, SETTING_CY) filter.zoom = obs.obs_data_get_double(settings, SETTING_ZOOM) filter.rotate = obs.obs_data_get_double(settings, SETTING_ROT) --set_render_size(filter) end source_info.video_render = function(filter) local parent = obs.obs_filter_get_parent(filter.source) filter.width = obs.obs_source_get_base_width(parent) filter.height = obs.obs_source_get_base_height(parent) obs.obs_source_process_filter_begin(filter.source, obs.GS_RGBA, obs.OBS_NO_DIRECT_RENDERING) obs.gs_effect_set_float(filter.params.pos_cx, filter.pos_cx) obs.gs_effect_set_float(filter.params.pos_cy, filter.pos_cy) obs.gs_effect_set_float(filter.params.zoom, filter.zoom) obs.gs_effect_set_float(filter.params.rotate, filter.rotate) obs.gs_effect_set_int(filter.params.width, filter.width) obs.gs_effect_set_int(filter.params.height, filter.height) obs.obs_source_process_filter_end(filter.source, filter.effect, filter.width, filter.height) end shader = [[ //Pan Zoom Rotate effect filter by khaver uniform float4x4 ViewProj; uniform texture2d image; uniform float pos_cx; uniform float pos_cy; uniform float zoom; uniform float rotate; uniform int width; uniform int height; sampler_state textureSampler { Filter = Linear; AddressU = Border; AddressV = Border; BorderColor = 00000000; }; struct VertData { float4 pos : POSITION; float2 uv : TEXCOORD0; }; VertData VSDefault(VertData v_in) { VertData vert_out; vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); vert_out.uv = v_in.uv; return vert_out; } float2x2 rotate2d (float _angle) { return float2x2(cos(_angle), -sin(_angle), sin(_angle), cos(_angle)); } float4 ps_main(VertData v_in) : TARGET { if (zoom == 0.0) return float4(0,0,0,0); if (pos_cx == 0.0 && pos_cy == 0.0 && zoom == 1.0 && rotate == 0.0) return image.Sample(textureSampler, v_in.uv); float AspRat = float(width) / float(height); float2 XYscale = pow(max(0.0001.xx, zoom), 2.0); float2 pos = float2(pos_cx + 0.5, pos_cy + 0.5); float2 xy1 = v_in.uv - 0.5.xx; float angle = radians(rotate); xy1.x *= AspRat; xy1 = mul(rotate2d(angle), xy1); xy1.x /= AspRat; xy1 = ((xy1 + (float2(0.5 - pos.x, pos.y - 0.5) * (XYscale + 1.0.xx))) / XYscale) + 0.5.xx; return image.Sample(textureSampler, xy1); //pixel); } technique Draw { pass { vertex_shader = VSDefault(v_in); pixel_shader = ps_main(v_in); } } ]]