Режим Скриптування на Python – Python Scripting Mode

The Python Scripting mode offers full programmable line stylizes. In this control mode, all styling operations are written as Python scripts referred to as style modules in the Freestyle terminology. The input to a style module is a view map (i.e. a set of detected feature edges), and the output is a set of stylized strokes.

Модуль стилю складається з послідовних викликів п’яти базових операторів: виділення – selection, зчіплювання – chaining, розділення – splitting, сортування – sorting та створення штриха – stroke creation. Оператор виділення – selection ідентифікує піднабір уводу вирізнених країв на основі однієї чи кількох визначених користувачем умов виділення (предикатів, тверджень). Виділені краї обробляються операторами зчіплювання, розділення та сортування для побудови ланцюгів вирізнених країв. Ці оператори також керуються заданими користувачем предикатами та функціями, щоб визначати, як трансформувати вирізнені краї у ланцюги. Нарешті, ланцюги трансформуються у стилізовані штрихи оператором створення штриха, який приймає список визначених користувачем відтінювачів штриха.

Модулі стилю Python зберігаються у межах blend-файлів як блоки даних тексту. Зовнішні файли модулів стилю спершу необхідно завантажити у Редактор Тексту – Text Editor. Далі меню вибору у межах запису стеку модулів стилю дозволяє вам обрати модуль зі списку завантажених модулів стилю.

../../_images/render_freestyle_python_scripting-mode.png

A screen capture of a style module cartoon.py loaded in the Text Editor (left), as well as Freestyle options in the Python Scripting mode in the View Layers buttons (right).

Freestyle для Blender поставляється з низкою модулів стилю Python, що можуть слугувати відправною точкою для написання вашого власного модуля стилю. Дивіться підрозділ Freestyle Python API у посібнику Blender Python API про деталі конструювання модуля стилю.

../../_images/render_freestyle_python_scripting-mode-example-1.jpg

By T.K. using the Python Scripting mode (blend-file, CC0).

../../_images/render_freestyle_python_scripting-mode-example-2.png

By T.K. using the Python Scripting mode (blend-file, CC0).

Написання модулів стилю

Модуль стилю – це шматок коду, відповідальний за стилізацію прорису ліній Freestyle. Увід модуля стилю – це набір вирізнених країв, що називається картою огляду – view map (ViewMap). Вивід – це набір стилізованих ліній, що також відомі, як штрихи. Модуль стилю структурований як конвеєр операцій, що дозволяють вибудовувати штрихи з увідних країв у межах карти огляду.

Існує п’ять видів операцій (перераховані з відповідними функціями оператора):

  • Виділення – Selection Operators.select()
  • Зчіплювання – Chaining Operators.chain(), Operators.bidirectional_chain()
  • Розділення – Splitting Operators.sequential_split(), Operators.recursive_split()
  • Сортування – Sorting Operators.sort()
  • Створення штриха – Stroke creation Operators.create()

Увідна карта огляду заповнюється набором об’єктів ViewEdge. Операція виділення використовується для вибору ViewEdges, що представляють інтерес для митців на основі визначених користувачем умов (предикатів) виділення. Операції зчіплювання приймають піднабір ViewEdges та будують Ланцюги, зчіплюючи ViewEdges відповідно до визначених користувачем предикатів та функцій. Ці Ланцюги можуть бути далі уточнені, розділенням їх на менші шматки (наприклад, у точках, де краї роблять гострий поворот) та виділенням частини їх (наприклад, для збереження тільки тих, що довші, ніж поріг довжини). Операція сортування використовується для впорядкування ланцюгів у стеку для прорису однієї лінії поверхн іншої. Ланцюги фінально трансформуються у стилізовані штрихи операцією створення штрихів шляхом застосування серії відтінювачів штрихів до окремих ланцюгів.

ViewEdges, Chains та Strokes загалом називаються одновимірними (1D) елементами. 1D елемент – це полілінія, що є серією з’єднаних прямих ліній. Вершини 1D елементів називаються 0D елементами, у загальному.

Усі оператори діють на наборі активних 1D елементів. Початковий активний набір – це набір ViewEdges в увідній карті огляду. Активний набір оновлюється операторами.

Виділення – Selection

Оператор виділення, вибору проходить через кожен елемент активного набору та зберігає тільки ті, які задовільняють вимоги певного предиката. Метод Operators.select() приймає як аргумент одноаргументний предикат, що працює на будь-якому Interface1D, що представляє 1D елемент. Наприклад:

Operators.select(QuantitativeInvisibilityUP1D(0))

Ця операція виділення використовує предикат QuantitativeInvisibilityUP1D для вибору тільки видимих ViewEdge (більш точно тих, яких кількісна невидимість дорівнює 0). Оператор виділення наміряється вибірково застосувати стиль до частини активних 1D елементів.

Відзначено, що QuantitativeInvisibilityUP1D – це клас реалізації предиката, що перевіряє видимість лінії, а метод Operators.select() приймає примірник класу предиката як аргумент. Перевірка предиката для даного 1D елемента фактично робиться викликом примірника предикати, тобто, залучаючи метод __call__ класу предиката. Іншими словами, метод Operators.select() приймає як аргумент функтор – functor, який, у свою чергу, приймає об’єкт Interface0D як аргумент. Freestyle Python API широко вживає функтори для реалізації предикатів, а також функцій.

Зчіплювання – Chaining

Оператори зчіплювання діють на наборі активних об’єктів ViewEdge та визначають топологію майбутніх штрихів. Ідея полягає в реалізації повторювача – iterator для проходження графа ViewMap шляхом пересування уздовж ViewEdges. Повторювач визначає правило зчіплювання, яке визначає наступний ViewEdge для слідування у задану вершину (дивіться ViewEdgeIterator). Кілька таких повторювачів надаються як частина Freestyle Python API (дивіться ChainPredicateIterator та ChainSilhouetteIterator). Власні користувацькі повторювачі можуть визначатися успадковуванням класу ViewEdgeIterator. Оператор зчіплювання також приймає як аргумент UnaryPredicate, що працює на Interface1D, як критерій зупинки. Зчіплювання зупиняється, коли повторювач досяг задоволення ViewEdge умов цього предикату у ході пересування по графу.

Зчіплювання може бути однонапрямним Operators.chain() або двонапрямним Operators.bidirectional_chain(). В останньому випадку, зчіплювання буде поширюватися у двох напрямках від стартового краю.

Наступне є прикладом коду двонапрямного зчіплювання:

Operators.bidirectional_chain(
        ChainSilhouetteIterator(),
        NotUP1D(QuantitativeInvisibilityUP1D(0)),
        )

Оператор зчіплювання використовує ChainSilhouetteIterator як правило зчіплювання та зупиняє зчіплювання зразу ж, як повторювач прийшов до невидимого ViewEdge.

Оператори зчіплювання обробляють набір активних об’єктів ViewEdge за порядком. Активні ViewEdges можуть попередньо бути сортовані за допомогою методу Operators.sort() (дивіться нижче). Він запускає ланцюг з першого ViewEdge активного набору. Усі ViewEdges, що вже були залучені у процес зчіплювання, позначаються (у випадку прикладу вище, штамп часу кожного ViewEdge модифікується стандартно), щоб не обробляти двічі один і той же ViewEdge. Після того, як зчіплювання досягає ViewEdge, що задовільняє умовам предиката зупинки, ланцюг завершується. Далі новий ланцюг починається з першого непозначеного ViewEdge в активному наборі. Ця операція повторюється, допоки останній непозначений ViewEdge з активного набору не буде оброблено. У кінці операції зчіплювання, активний набір – це набір Ланцюгів, що були побудовані.

Розділення – Splitting

Операція розділення використовується для уточнення топології кожного Ланцюга. Розділення здійснюється послідовно або рекурсивно. Послідовне розділення Operators.sequentialSplit() у своїй базовій формі, аналізує Ланцюг у заданій довільній роздільності та оцінює одноаргументний предикат (працюючи на 0D елементах) у кожній точці уздовж цього Ланцюга. Кожен раз, при задоволенні предиката, ланцюг розділюється на два ланцюги. У кінці операції послідовного розділення активний набір ланцюгів є набором нових ланцюгів.

Operators.sequentialSplit(TrueUP0D(), 2)

In this example, the chain is split every 2 units. A more elaborated version uses two predicates instead of one: One to determine the starting point of the new chain and the other to determine its ending point. This second version can lead to a set of Chains that are disjoint or that overlap if the two predicates are different (see Operators.sequentialSplit() for more details).

Рекурсивне розділення Operators.recursiveSplit() оцінює функцію на 0D елементах уздовж Ланцюга у заданій роздільності та знаходить точку, що дає максимальне значення для цієї функції. Ланцюг далі розділяється на два у цій точці. Цей процес рекурсивно повторюється на кожному з двох нових Ланцюгів, допоки увідний Ланцюг не буде задовольняти визначеній користувачем умові зупинення.

func = Curvature2DAngleF0D()
Operators.recursive_split(func, NotUP1D(HigherLengthUP1D(5)), 5)

У прикладі коду вище, Ланцюги рекурсивно розділяються у точках найвищої 2D кривини. Ця кривина оцінюється у точках уздовж Ланцюга з роздільністю 5 одиниць. Ланцюги, коротші, ніж 5 одиниць, не будуть більше розділятися.

Сортування – Sorting

Оператор сортування Operators.sort() впорядковує порядок нашарування активних 1D елементів. Він приймає як аргумент двоаргументний предикат, використовуваний як оператор «менше ніж» до порядку 1D елементів.

Operators.sort(Length2DBP1D())

У цьому прикладі коду, сортування використовує двоаргументний предикат Length2DBP1D для сортування об’єктів Interface1D у висхідному порядку у термінах 2D довжини.

Сортування особливо корисне, коли комбінується з щільністю причин. Дійсно, щільність причин оцінює щільність результатного зображення при його модифікації. Якщо ми бажаємо використати такий інструмент для вирішення того, що слід вилучити штрихи кожен раз, коли локальна щільність є надто високою, то важливо контролювати порядок, в якому ці штрихи прорисовуються. У цьому випадку, ми скористаємося оператором сортування для гарантування, що більш «важливі» лінії прорисуються першими.

Створення Штриха – Stroke Creation

Фінально, оператор створення штрихів Operators.create() приймає активний набір Ланцюгів як увід та будує Штрихи. Цей оператор приймає два аргументи. Перший – це одноаргументний предикат, що працює на Interface1D, який призначений для зроблення останнього виділення на наборі ланцюгів. Ланцюг, що не задовільняє цій умові, не перейде далі у Штрих. Другий увід – це список відтінювачів, що будуть відповідати за відтінення кожного побудованого штриха.

shaders_list = [
    SamplingShader(5.0),
    ConstantThicknessShader(2),
    ConstantColorShader(0.2,0.2,0.2,1),
    ]
Operators.create(DensityUP1D(8,0.1, IntegrationType.MEAN), shaders_list)

У цьому прикладі, предикат DensityUP1D використовується для вилучення усіх Ланцюгів, які мають середню щільність, вище за 0.1. Кожен ланцюг трансформується у штрих шляхом повторного відбору так, щоб мати точку через кожні 5 одиниць, призначення для нього постійної товщини у 2 одиниці та темно-сірого постійного кольору.

Керування користувачем конвеєром визначення

Написання модуля стилю пропонує різні типи керування користувачем, навіть хоча окремі модулі стилю мають фіксовану структуру конвеєра. Одним з них є задання послідовності різних керувальних структур конвеєра, а іншим – через визначення об’єктів функторів, що передаються як аргумент уздовж усього конвеєра.

Різні структури керування конвеєром можуть бути визначені заданням операцій виділення, зчіплювання, розділення та сортування. Створення штриха є завжди останньою операцією, що завершує модуль стилю.

Предикати, функції, повторювачі зчіплювання та відтінювачі штрихів можуть визначатися успадковуванням базових класів та перевизначенням відповідних методів. Для отримання додаткової інформації про визначувані користувачем конструкції дивіться відповідні записи про наступні базові класи.

Дивись також

Predicates, functions, chaining iterators, and stroke shaders can be defined by inheriting base classes and overriding appropriate methods. See Freestyle python module for more information on the user-scriptable constructs.