Русский
Русский
English
Статистика
Реклама

Filter

Перевод Три способа создания клякс с помощью CSS и SVG

07.03.2021 22:07:07 | Автор: admin

Кляксы (Blob) - это гладкие, аморфные, желеобразные формы, обычно причудливые и забавные. Их можно использовать в качестве элементов иллюстраций и фоновых эффектов в сети.

Итак, как же они устроены? Разумеется, можно открыть какой-то графический редактор и сделайте их, верно? Конечно, это круто. Но мы пишем здесь о CSS финтах, и было бы гораздо интереснее посмотреть на возможности, которые нам дают CSS и SVG - двух наших любимых ингредиентов!

У нас есть несколько способов сделать кляксы. Давай проверим их.

Рисуем круги в SVG

Начнем с чего-то простенького. Мы можем рисовать SVG в чем-то вроде Illustrator, Sketch, Figma или чем-то ещё, но вместо этого мы будем программировать SVG.

<circle cx="100" cy="100" r="40" fill="red" />

SVG делает рисование круга довольно тривиальным благодаря элементу <circle> с соответствующим значениями:

cxопределяет координату X центра окружности.

cy определяет координату Y.

r - радиус.

fill используется для заливки формы цветом.

Этот фрагмент создает круг с радиусом 40px с центром в точке 100px по оси X и 100px по оси Y. Координаты отсчитываются с верхнего левого угла родительского контейнера.

Давайте создадим несколько перекрывающихся кругов следующим образом:

<svg height="300" width="300">  <circle cx="80" cy="80" r="40" fill="red" />  <circle cx="120" cy="80" r="40" fill="red" />  <circle cx="150" cy="80" r="40" fill="red" />  <circle cx="150" cy="120" r="40" fill="red" />  <circle cx="100" cy="100" r="40" fill="red" /></svg>

<svg>действует как холст, на котором нарисованы все различные формы и фигуры. Его значения высоты и ширины указывают на размер, в который должен быть заключен весь рисунок. Если какая-то часть фигуры выходит за пределы размера SVG, эта часть будет обрезана.

Но кляксы не всегда такие идеально круглые... Мы можем смешать объекты, используя <ellipse> вместо <circle>:

<ellipse cx="200" cy="80" rx="100" ry="50" fill="red" />

Этот элемент очень похож на круг, за исключением имени тега и двух значений радиуса, чтобы определить горизонтальный (rx) и вертикальный (ry) радиусы по отдельности. Забавно то, что мы все равно можем получить правильный круг, если значения радиусов будут одинаковыми. Так что в некотором смысле <ellipse> немного более универсальный круг.

Если бы всё, что нам было нужно - это круг, мы, вероятно, могли бы использовать CSS без SVG. Любой прямоугольный элемент может стать кругом или эллипсом с правильно заданным значением border-radius.

.circle {  border-radius: 50%;  height: 50px;  width: 50px;}

но об этом немного позже.

Фристайл с SVG-путями

Благодаря тегу <path> в SVG мы можем создавать любые формы. Это как рисовать карандашом или ручкой. Вы начинаете с точки и рисуете линии, кривые, формы, а потом замыкаете путь.

В <path> есть много параметров для различных задач, например:

M Переход к точке

L Рисование линии

C Рисование кривой

Q Кривые Безье

Z Закрывание пути

Нам просто нужен параметр кривой (C) для примитивной кляксы. Но мы также переместим начальную точку и закроем путь, так что мы также воспользуемся параметрами M и Z.

Координаты играют большую роль в теге, поэтому то, что мы собираемся рассмотреть, будет выглядеть как данные Google Maps, заблокированные внутри нашего кода. Но это становится более логичным, когда мы знаем, что они делают.

Попробуем это

<svg xmlns="http://personeltest.ru/away/www.w3.org/2000/svg">  <path    fill="#24A148"    d=""  /></svg>

Здесь атрибут d хранит данные пути. Он содержит информацию о том, где начинается рисунок, в каком направлении он движется, какой форме следует и где заканчивается. Например:

<path d="M 10 10 C 20 20, 40 20, 50 10" stroke="black" fill="transparent"/>

Это показывает, что наш путь начинается с координат (10 10), обозначенных буквой M перед ними. Затем он устанавливает кубическую кривую Безье (C) с двумя контрольными точками. Кривые Безье похожи на ручки на обоих концах пути, которые контролируют изгиб между ними. У нас есть две ручки Безье: одна для начального положения (20 20) кривой, а другая для конечного положения (40 20).

Давайте воспользуемся этими знаниями для создания нашего большого двоичного объекта.

Нарисованная мной клякса, на самом деле, немного сложна, с её множеством кривых и контрольных точек. Несколько смущает, что многие координаты не являются целыми числами, но, тем не менее, теперь, когда мы знаем, что делает параметр d в теге <path> и какие атрибуты он использует для рисования точек на пути, это не выглядит так страшно.

Очевидно, что это большой объем кода, который нужно не только написать вручную, но и сделать все правильно. Но благо, для этого есть инструменты, которые облегчат вашу жизнь.

www.blobmaker.app

Эффекты липкости с фильтрами CSS и SVG

Правда SVG <path> сложен? Что, если я представлю вам способ преобразовать множество пользовательских фигур (которые вы можете создавать с помощью div) в липкие кляксы? Идея состоит в следующем - мы собираемся создать два пересекающихся прямоугольника. Они одного цвета, но имеют небольшую прозрачность, чтобы затемнить места пересечения.

Затем мы используем функции размытия SVG, чтобы размазать прямоугольники, создав дополнительное липкое пятно с более мягкими краями.

Два пересекающихся прямоугольника превратятся в это

Давайте сначала разберемся, как работают фильтры в SVG. Они объявляются с помощью тега <filter> в элементах HTML или других элементах SVG, например, для тега <circle> можем применить CSS правило.

circle {  filter: url("#id_of_filter");}

<filter> - это, по сути, оболочка для фактических эффектов фильтра, которые включают:

  • <feGaussianBlur>

  • <feImage>

  • <feMerge>

  • <feColorMatrix>

Наша клякса размытая и цветная, поэтому мы собираемся использовать <feGaussianBlur>и <feColorMatrix>.

<feGaussianBlur>принимает несколько атрибутов, но нас интересуют только два из них: сколько размытия мы хотим и где мы этого хотим. Стандартное отклонение (stdDeviation) и свойства in соответствуют нашим запросам.

in принимает одно из двух значений:

SourceGraphic - размывает всю форму

SourceAlpha - размывает альфа-значение и используется для создания теневых эффектов.

Немного поигравшись, я обнаружил эффект <feGaussianBlur>:

<feGaussianBlur in="SourceGraphic" stdDeviation="30" />

Это вставляется прямо в разметке HTML с идентификатором, который мы вызываем для родительского элемента нашего большого двоичного объекта:

<!-- The SVG filter --><svg style="position: absolute; width: 0; height: 0;">  <filter id="goo">    <feGaussianBlur in="SourceGraphic" stdDeviation="30" />  </filter></svg><!-- The blob --><div class="hooks-main">  <div></div>  <div></div></div>

Фильтр на самом деле не отображается, даже если он находится в разметке. Вместо этого мы ссылаемся на него как на фильтр CSS в родительском элементе большого двоичного объекта:

Мдассс, это пока не то что нам надо. Размытие расфокусировано, а форма элемента потеряла границу и цвет. Нам нужен эффект выпуклости с размытием границ и сплошной цвет для заливки формы. Здесь в игру вступает наш следующий фильтр SVG, <feColorMatrix>.

Нам нужны два атрибута <feColorMatrix> :

in - указывает, где применяется эффект, как и <feGaussianBlur>.

values - матрица из четырех строк и пяти столбцов.

Атрибут values имеет немного больше нюансов. Он содержит матрицу, которая умножается на значения цвета и альфа канала каждого пикселя и генерирует новое значение цвета для этого пикселя. Математически говоря:

new pixel color value = ( values matrix )  ( current pixel color value )

Немного математики в наших трансформациях. В этом уравнении матрица значений равна:

[F-red1 F-green1 F-blue1 F-alpha1 F-constant1 F-red2 F-green2 F-blue2 F-alpha2 F-constant2 F-red3 F-green3 F-blue3 F-alpha3 F-constant3 F-red4 F-green4 F-blue4 F-alpha4 F-constant4]

Здесь F-red означает долю красного в пикселях со значением от 0 до 1.

F-constant - это некоторое постоянное значение, которое нужно добавить (или вычесть) из значения цвета.

Разбиваем эти значения дальше

У нас есть цветной пиксель со значением RGBA rgba (214, 232, 250, 1). Чтобы преобразовать его в новый цвет, мы умножим его на нашу матрицу значений.

Значение пикселя не изменилось, потому что мы умножили его на единичную матрицу, но если вы измените, значения матрицы, то изменится и ее значение в пикселях.

Узнайте больше о матрице значений из документации MDN.

В нашем случае эти значения работают очень хорошо:

<filter id="goo">  <feGaussianBlur in="SourceGraphic" stdDeviation="30" />  <feColorMatrix    in="blur"    values="1 0 0 0 0             0 1 0 0 0             0 0 1 0 0             0 0 0 30 -7"  /></filter>

Я добавил еще несколько стилей в кляксу, чтобы растянуть её из угла.

Попробуйте использовать эти значения фильтра в других формах и дайте мне знать, как они работают для вас, в комментариях.

Использование CSS border-radius

Как упоминалось раньше, можно создать кляксу и при помощи CSS свойстваborder-radius. Он также может создавать формы, похожие на капли, благодаря способности сглаживать углы элемента. Это возможно, потому что каждый угловой радиус разделен на два радиуса, по одному для каждой кромки. Вот почему у нас может быть больше форм, кроме круга и эллипса.

Возможно, вы привыкли использовать border-radius как сокращение для всех четырех углов элемента:

.rounded {  border-radius: 25%;}

Это хороший способ добиться единообразия всех углов. Но кляксы не такие однородные. Мы хотим, чтобы одни углы были более округлыми, чем другие, чтобы некоторые из них выглядели липкими. Вот почему мы выбираем составляющие свойства border-radius, например:

.element {  border-top-left-radius: 70% 60%;  border-top-right-radius: 30% 40%;  border-bottom-right-radius: 30% 60%;  border-bottom-left-radius: 70% 40%;}

Как можно видеть каждое свойство принимает два значения. По одному на каждый край угла, что дает нам большую гибкость, чтобы изгибать элемент в интересные формы. Затем мы можем добавить цвет фона, заполнить его градиентом или даже установить на нем тень, чтобы получить аккуратный эффект.

Подробнее..

OBS Studio Lua Скриптинг. Часть 2

06.10.2020 16:11:14 | Автор: admin

Всем привет, в этой части руководства рассмотрим:
фильтры, сцены, предметы сцен, Frontend API, создание функциональных фильтров и прочее
С первой частью можно ознакомиться по этой ссылке.


КДПВ сделана в OBS 26.0.0


Краткая справка для этой части


  • Источник Источники используются для рендера аудио/видео, например: захват камеры, игры, звука. С помощью источников можно создавать фильтры, переходы


  • Фильтр Источник который дополняет другие источники


  • Сцены Коллекция источников, сцена является источником ( сцену можно добавить как источник в другой сцене)


  • Предмет сцены конкретный источник в сцене, его можно: перемещать, увеличивать/уменьшать, переворачивать, менять состояние выкл/вкл и.т.д


  • Frontend API Набор функций который предоставляет OBS Studio, например:


    • подписка на событие о переключении сцен
    • запрос статуса о том, идёт ли стрим/запись
    • вкл/выкл стрим/запись
    • переключение сцен


Фильтры


Типы фильтров так же как и источников, можно узнать через функцию obs_source_get_unversioned_id


Название Внутреннее представление типа
Компрессор compressor_filter
Экспандер expander_filter
Усиление gain_filter
Инвертировать полярность invert_polarity_filter
Лимитер limiter_filter
Пропускной уровень шума noise_gate_filter
Шумоподавление noise_suppress_filter
VST 2.x плагин vst_filter
Задержка видео (асинхронность) async_delay_filter
Хромакей chroma_key_filter
Коррекция цвета color_filter
Цветовой ключ color_key_filter
Кадрирование crop_filter
Маска изображения/Смешивание mask_filter
Яркостный ключ luma_key_filter
Задержка отображения gpu_delay
Масштабирование/Соотношение сторон scale_filter
Прокрутка scroll_filter
Увеличить резкость sharpness_filter

В английском варианте: ссылка


Скрипт: изменение параметра прозрачности у фильтра на случайную величину от 1 до 100.


Чтобы узнать название параметра "прозрачность" необходимо добавить фильтр с прозрачностью на какой-нибудь источник, изменить этот параметр. Далее открыть файл коллекции сцен, путь к директории можно узнать через меню OBS:
Справка > Файлы журнала > Показать файлы журнала
далее с этой директории поднимаемся выше, и получаем путь ~/basic>scenes>название_сцены.json
В этом файле ищем color_filter или color_key_filter (оба фильтра могут изменить прозрачность источника).
В строке settings видим что прозрачность записана как opacity.
Ещё один способ узнать название параметра, прочитать исходный код фильтра ссылка


Находим источник по имени


function add_filter_to_source(random_n)  source = obs.obs_get_source_by_name(source_name)

Создаём настройки с изменением параметра opacity на случайное число


settings = obs.obs_data_create()obs.obs_data_set_int(settings, "opacity",random_n)

Проверяем существует ли уже фильтр на источнике, если нет добавляем


_color_filter = obs.obs_source_get_filter_by_name(source,"opacity_random")if _color_filter == nil then -- if not exists  _color_filter = obs.obs_source_create_private( "color_filter", "opacity_random", settings)  obs.obs_source_filter_add(source, _color_filter)end

Обновляем и освобождаем память


  obs.obs_source_update(_color_filter,settings)  obs.obs_source_release(source)  obs.obs_data_release(settings)  obs.obs_source_release(_color_filter)end

Привязка к горячей клавише


function htk_1_cb(pressed)   if pressed then    n = math.random(1,100)    add_filter_to_source(n)  endend

Гифка


Исходный код
local obs = obsluasource_name = ''function htk_1_cb(pressed)   if pressed then    n = math.random(1,100)    add_filter_to_source(n)  endendfunction add_filter_to_source(random_n)  source = obs.obs_get_source_by_name(source_name)  settings = obs.obs_data_create()  obs.obs_data_set_int(settings, "opacity",random_n)  _color_filter = obs.obs_source_get_filter_by_name(source,"opacity_random")  if _color_filter == nil then -- if not exists    _color_filter = obs.obs_source_create_private( "color_filter", "opacity_random", settings)    obs.obs_source_filter_add(source, _color_filter)  end  obs.obs_source_update(_color_filter,settings)  obs.obs_source_release(source)  obs.obs_data_release(settings)  obs.obs_source_release(_color_filter)endfunction script_properties()  -- source https://raw.githubusercontent.com/insin/obs-bounce/master/bounce.lua  local props = obs.obs_properties_create()  local source = obs.obs_properties_add_list(    props,    'source',    'Source:',    obs.OBS_COMBO_TYPE_EDITABLE,    obs.OBS_COMBO_FORMAT_STRING)  for _, name in ipairs(get_source_names()) do    obs.obs_property_list_add_string(source, name, name)  end  return propsendfunction script_update(settings)  source_name = obs.obs_data_get_string(settings, 'source')end--- get a list of source names, sorted alphabeticallyfunction get_source_names()  local sources = obs.obs_enum_sources()  local source_names = {}  if sources then    for _, source in ipairs(sources) do      -- exclude Desktop Audio and Mic/Aux by their capabilities      local capability_flags = obs.obs_source_get_output_flags(source)      if bit.band(capability_flags, obs.OBS_SOURCE_DO_NOT_SELF_MONITOR) == 0 and        capability_flags ~= bit.bor(obs.OBS_SOURCE_AUDIO, obs.OBS_SOURCE_DO_NOT_DUPLICATE) then        table.insert(source_names, obs.obs_source_get_name(source))      end    end  end  obs.source_list_release(sources)  table.sort(source_names, function(a, b)    return string.lower(a) < string.lower(b)  end)  return source_namesendkey_1 = '{"htk_1": [ { "key": "OBS_KEY_1" } ]}'json_s = key_1default_hotkeys = {  {id='htk_1',des='Кнопка 1 ',callback=htk_1_cb},}function script_load(settings)  s = obs.obs_data_create_from_json(json_s)  for _,v in pairs(default_hotkeys) do     a = obs.obs_data_get_array(s,v.id)    h = obs.obs_hotkey_register_frontend(v.id,v.des,v.callback)    obs.obs_hotkey_load(h,a)    obs.obs_data_array_release(a)  end  obs.obs_data_release(s)end

Стоит упомянуть также о функции obs_source_enum_filters с её помощью можно получить
список всех фильтров у конкретного источника, кстати эта функция не работает в obspython,
но об этом чуть позже.


function check()  source = obs.obs_get_source_by_name(source_name)  result = obs.obs_source_enum_filters(source)  for k,v in pairs(result) do     name = obs.obs_source_get_name(v)    print('name'.. name)  end  obs.source_list_release(result)  obs.obs_source_release(source)end

Эвенты и состояние


Скрипт: звуковое оповещение о том что сцена изменена, с использованием .mp3 файла.
На основе этого скрипта


Создадим функцию для проигрывания звука при смене сцен.


function on_event(event)   if event == obs.OBS_FRONTEND_EVENT_SCENE_CHANGED    then obs_play_sound_release_source()  end end

Добавим источник медиа, установим настройки: файл alert.mp3 относителен директории нахождения
скрипта, obs_source_set_monitoring_type выставляет прослушивание аудио.


function play_sound()  mediaSource = obs.obs_source_create_private("ffmpeg_source", "Global Media Source", nil)  local s = obs.obs_data_create()  obs.obs_data_set_string(s, "local_file",script_path() .. "alert.mp3")  obs.obs_source_update(mediaSource,s)  obs.obs_source_set_monitoring_type(mediaSource,obs.OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT)  obs.obs_data_release(s)  obs.obs_set_output_source(outputIndex, mediaSource)  return mediaSourceendfunction obs_play_sound_release_source()  r = play_sound()  obs.obs_source_release(r)end

Исходный код
local obs = obsluamediaSource = nil -- Null pointeroutputIndex = 63 -- Last indexfunction play_sound()  mediaSource = obs.obs_source_create_private("ffmpeg_source", "Global Media Source", nil)  local s = obs.obs_data_create()  obs.obs_data_set_string(s, "local_file",script_path() .. "alert.mp3")  obs.obs_source_update(mediaSource,s)  obs.obs_source_set_monitoring_type(mediaSource,obs.OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT)  obs.obs_data_release(s)  obs.obs_set_output_source(outputIndex, mediaSource)  return mediaSourceendfunction obs_play_sound_release_source()  r = play_sound()  obs.obs_source_release(r)endfunction on_event(event)   if event == obs.OBS_FRONTEND_EVENT_SCENE_CHANGED    then obs_play_sound_release_source()  end endfunction script_load(settings)  obs.obs_frontend_add_event_callback(on_event)endfunction script_unload()  obs.obs_set_output_source(outputIndex, nil)end

Время и файлы


Запись в файл, "a" создаст(если нет) файл и добавит "content", а "w" перезапишет .


io.output(io.open(script_path() .. "out.txt","a"))io.write("content")io.close()

print(os.date("%c"))-- День недели Месяц Время Год


Сцены и предметы сцен


  • obs_sceneitem_get_source предметы сцен в источник
  • obs_scene_from_source преобразование сцены в источник
  • obs_scene_find_source преобразование источника в предмет сцены
  • obs_frontend_get_scenes получение всех сцен, освобождать с source_list_release
  • obs_frontend_get_current_scene получение текущей сцены
  • obs_scene_enum_items список всех предметов в сцене, освобождать с sceneitem_list_release

Скрипт: включение и выключение предмета сцены(источника на сцене).


Получение всех сцен и предметов в них


function toggle_source()  scenes = obs.obs_frontend_get_scenes()  for _,scene in pairs(scenes) do    scene_source = obs.obs_scene_from_source(scene)    items = obs.obs_scene_enum_items(scene_source)...

Поиск конкретного источника и его включение или выключение, source_name и boolean определены глобально.


...for _,scene_item in pairs(items) do  _source = obs.obs_sceneitem_get_source(scene_item)  _name = obs.obs_source_get_name(_source)  if _name == source_name then    boolean = not boolean     obs.obs_sceneitem_set_visible(scene_item, boolean)  endend...

Гифка


Исходный код
local obs = obsluasource_name = ''boolean = truefunction htk_1_cb(pressed)   if pressed then    toggle_source()  endendfunction toggle_source()  scenes = obs.obs_frontend_get_scenes()  for _,scene in pairs(scenes) do    scene_source = obs.obs_scene_from_source(scene)    items = obs.obs_scene_enum_items(scene_source)    for _,scene_item in pairs(items) do      _source = obs.obs_sceneitem_get_source(scene_item)      _name = obs.obs_source_get_name(_source)      if _name == source_name then        boolean = not boolean         obs.obs_sceneitem_set_visible(scene_item, boolean)      end    end    obs.sceneitem_list_release(items)  end  obs.source_list_release(scenes)endfunction script_properties()  -- source https://raw.githubusercontent.com/insin/obs-bounce/master/bounce.lua  local props = obs.obs_properties_create()  local source = obs.obs_properties_add_list(    props,    'source',    'Source:',    obs.OBS_COMBO_TYPE_EDITABLE,    obs.OBS_COMBO_FORMAT_STRING)  for _, name in ipairs(get_source_names()) do    obs.obs_property_list_add_string(source, name, name)  end  obs.obs_property_set_long_description(source,"?" )  return propsendfunction script_update(settings)  source_name = obs.obs_data_get_string(settings, 'source')end--- get a list of source names, sorted alphabeticallyfunction get_source_names()  local sources = obs.obs_enum_sources()  local source_names = {}  if sources then    for _, source in ipairs(sources) do      -- exclude Desktop Audio and Mic/Aux by their capabilities      local capability_flags = obs.obs_source_get_output_flags(source)      if bit.band(capability_flags, obs.OBS_SOURCE_DO_NOT_SELF_MONITOR) == 0 and        capability_flags ~= bit.bor(obs.OBS_SOURCE_AUDIO, obs.OBS_SOURCE_DO_NOT_DUPLICATE) then        table.insert(source_names, obs.obs_source_get_name(source))      end    end  end  obs.source_list_release(sources)  table.sort(source_names, function(a, b)    return string.lower(a) < string.lower(b)  end)  return source_namesendkey_1 = '{"htk_1": [ { "key": "OBS_KEY_1" } ]}'json_s = key_1default_hotkeys = {  {id='htk_1',des='Кнопка 1 ',callback=htk_1_cb},}function script_load(settings)  s = obs.obs_data_create_from_json(json_s)  for _,v in pairs(default_hotkeys) do     a = obs.obs_data_get_array(s,v.id)    h = obs.obs_hotkey_register_frontend(v.id,v.des,v.callback)    obs.obs_hotkey_load(h,a)    obs.obs_data_array_release(a)  end  obs.obs_data_release(s)end

Регистрация фильтров


В obslua доступна функция obs_register_source, с её помощью можно зарегистрировать
источник( переходы и фильтры это источники). Для этого понадобится создать таблицу источника
Регистрация фильтров удобна тем, что позволяет закрепить функциональность скрипта за
определенным источником. Поддерживает горячие клавиши, интерфейс, таймеры.


Скрипт: закрепление горячих клавиш на фильтре, и полный доступ к источнику.


Импорт библиотеки, и определение типа как источник-фильтр.


local obs = obslualocal bit = require("bit")local info = {} -- obs_source_info https://obsproject.com/docs/reference-sources.htmlinfo.id = "uniq_filter_id"info.type = obs.OBS_SOURCE_TYPE_FILTERinfo.output_flags = bit.bor(obs.OBS_SOURCE_VIDEO)info.get_name = function() return 'default filter name' end

Инициализация фильтра, будет вызываться при запуске программы или при добавлении к источнику


info.create = function(settings,source)   local filter = {}  filter.context = source

Начальная регистрация горячих клавиш, принадлежащих конкретному фильтру.


filter.hotkeys = {  htk_stop = "[stop] ",  htk_restart = "[start] ",}filter.hotkey_mapping = function(hotkey,data)  if hotkey == "htk_stop" then    print('stop '.. data.srsn .. " : " .. data.filn)  elseif hotkey == "htk_restart" then    print('restart ' .. data.srsn .. " : " .. data.filn)  endendfilter.hk = {}for k,v in pairs(filter.hotkeys) do   filter.hk[k] = obs.OBS_INVALID_HOTKEY_IDend

Создание функции которая запустится не сразу ( это необходимо т.к фильтр ещё не создан)
Он будет создан после return


filter._reg_htk = function()    info.reg_htk(filter,settings)  end  obs.timer_add(filter._reg_htk,100) -- callback to register hotkeys, one time only

Завершающая регистрация горячих клавиш,obs_filter_get_parent источник который фильтруется
к которому прикреплён фильтр этого типа. Удаление таймера.


info.reg_htk = function(filter,settings) -- register hotkeys after 100 ms since filter was created  local target = obs.obs_filter_get_parent(filter.context)  local srsn = obs.obs_source_get_name(target)   local filn =  obs.obs_source_get_name(filter.context)  local data = {srsn = srsn, filn = filn}   for k, v in pairs(filter.hotkeys) do     filter.hk[k] = obs.obs_hotkey_register_frontend(k, v .. srsn .. " : " .. filn, function(pressed)    if pressed then filter.hotkey_mapping(k,data) end end)    local a = obs.obs_data_get_array(settings, k)    obs.obs_hotkey_load(filter.hk[k], a)    obs.obs_data_array_release(a)  end  obs.remove_current_callback()end

Необходимый код для пропуска фильтрации, без него при добавлении фильтра источник "выключится"


info.video_render = function(filter, effect)   -- called every frame  local target = obs.obs_filter_get_parent(filter.context)  if target ~= nil then    filter.width = obs.obs_source_get_base_width(target)    filter.height = obs.obs_source_get_base_height(target)  end  obs.obs_source_skip_video_filter(filter.context) endinfo.get_width = function(filter)  return filter.widthendinfo.get_height = function(filter)  return filter.heightend

Функция .save вызывается при сохранении настроек, т.е можно переназначить горячие клавиши.
obs.obs_register_source(info) регистрация фильтра, теперь его видно при нажатии ПКМ


info.save = function(filter,settings)  for k, v in pairs(filter.hotkeys) do    local a = obs.obs_hotkey_save(filter.hk[k])    obs.obs_data_set_array(settings, k, a)    obs.obs_data_array_release(a)  endendobs.obs_register_source(info)

info.load также как и script_load, вызывается при запуске программы, но в данном
случае дублирует функциональность и требует перезапуска. .update, .get_properties
функции аналогичные script_update, script_properties.


Гифка


Исходный код
local obs = obslualocal bit = require("bit")local info = {} -- obs_source_info https://obsproject.com/docs/reference-sources.htmlinfo.id = "uniq_filter_id"info.type = obs.OBS_SOURCE_TYPE_FILTERinfo.output_flags = bit.bor(obs.OBS_SOURCE_VIDEO)info.get_name = function() return 'default filter name' endinfo.create = function(settings,source)   local filter = {}  filter.context = source  filter.hotkeys = {    htk_stop = "[stop] ",    htk_restart = "[start] ",  }  filter.hotkey_mapping = function(hotkey,data)    if hotkey == "htk_stop" then      print('stop '.. data.srsn .. " : " .. data.filn)    elseif hotkey == "htk_restart" then      print('restart ' .. data.srsn .. " : " .. data.filn)    end  end  filter.hk = {}  for k,v in pairs(filter.hotkeys) do     filter.hk[k] = obs.OBS_INVALID_HOTKEY_ID  end  filter._reg_htk = function()    info.reg_htk(filter,settings)  end  obs.timer_add(filter._reg_htk,100) -- callback to register hotkeys, one time only  return filterendinfo.reg_htk = function(filter,settings) -- register hotkeys after 100 ms since filter was created  local target = obs.obs_filter_get_parent(filter.context)  local srsn = obs.obs_source_get_name(target)   local filn =  obs.obs_source_get_name(filter.context)  local data = {srsn = srsn, filn = filn}   for k, v in pairs(filter.hotkeys) do     filter.hk[k] = obs.obs_hotkey_register_frontend(k, v .. srsn .. " : " .. filn, function(pressed)    if pressed then filter.hotkey_mapping(k,data) end end)    local a = obs.obs_data_get_array(settings, k)    obs.obs_hotkey_load(filter.hk[k], a)    obs.obs_data_array_release(a)  end  obs.remove_current_callback()endinfo.video_render = function(filter, effect)   -- called every frame  local target = obs.obs_filter_get_parent(filter.context)  if target ~= nil then    filter.width = obs.obs_source_get_base_width(target)    filter.height = obs.obs_source_get_base_height(target)  end  obs.obs_source_skip_video_filter(filter.context) endinfo.get_width = function(filter)  return filter.widthendinfo.get_height = function(filter)  return filter.heightend--info.load = function(filter,settings) -- restart required--... same code as in info.reg_htk, but filters will be created from scratch every time--obs restarts, there is no reason to define it here again becuase hotkeys will be duplicated--endinfo.save = function(filter,settings)  for k, v in pairs(filter.hotkeys) do    local a = obs.obs_hotkey_save(filter.hk[k])    obs.obs_data_set_array(settings, k, a)    obs.obs_data_array_release(a)  endendobs.obs_register_source(info)

obspython


В OBS также доступен скриптинг через Python, для Windows только 3.6 версия, для Linux встроенная (т.к в настройках нельзя указать путь),
для MacOS Python не доступен для текущей (26.0.0) версии.
В отличии от Lua тут нельзя регистрировать источники, перебор фильтров не работает,
т.к не написан wrapper на функции с аргументом типа указатель-указатель.
Но в контексте скриптинга имеет место быть т.к:



Задачи


Перед тем как начать делать задачи, рекомендую сделать бэкап коллекции сцен,
с осторожностью использовать script_tick(вызывается раз в каждый кадр)
Проверять утечки памяти в папке logs, последняя строка последнего файла
пример время: Number of memory leaks: 0, если скрипт написан неправильно то
этой строчки там не окажется т.к OBS вылетит с ошибкой при закрытии.


3)[фильтры] "Динамическая прокрутка"
Создать программно или выбрать через интерфейс источник который будет фильтроваться,
к этом источнику добавить(если нет) фильтр Прокрутка (scroll_filter),
добавить интерфейс и/или горячие клавиши которые меняют значение вертикальной скорости
на случайную величину от 0 до 1000 при этом включать/выключать повторение с 50% шансом.


Гифка


4)[эвенты] "Проверка"
При переключении сцен проверять идёт ли запись.
Если нет вывести оповещение ( например через error())


5)[время и файлы] "Пост-продакшен"
Создать скрипт который при нажатии горячей клавиши записывает текущее время,
относительное время от старта записи, добавляет текст "МЕТКА",
а через интерфейс UI кнопку записать текст, и место для набора текста.
изображение


6)[предметы сцены] "Сумма"
Посчитать количество сцен и предметов сцен, записать ответ в названии первой сцены.
Не учитывать группы, т.к перебор предметов груп не работает.
Гифка


7) [фильтры и источники] "Нэйтив скриптинг"
Создать фильтр который будет с интервалом в 2 секунды включать и выключать источник за которым он закреплён.
Гифка


Ответы на задачи и код скриптов включая первую часть на Github


Ссылки


Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru