Difference between revisions of "UK:HowTo:Use POV-Ray with Blender/Developers"

From POV-Wiki
Jump to navigation Jump to search
m
 
Line 12: Line 12:
 
<table width=100% border=0 cellspacing=0 cellpadding=5>
 
<table width=100% border=0 cellspacing=0 cellpadding=5>
 
<tr><td width=33% bgcolor=#EEEEEF>
 
<tr><td width=33% bgcolor=#EEEEEF>
<font size="+2">[[HowTo:Use_POV-Ray_with_Blender/Developers|▼ Developer's page]]</font>
+
<font size="+2">[[HowTo:Use_POV-Ray_with_Blender/Developers|▼ Сторінка розробника]]</font>
 
</td>
 
</td>
 
<td width=33% align=center>[[File:POVExporterLogo.png|center|100px|link=https://extensions.blender.org/add-ons/povable]]</td>
 
<td width=33% align=center>[[File:POVExporterLogo.png|center|100px|link=https://extensions.blender.org/add-ons/povable]]</td>
 
<td width=33% bgcolor=#EEEEEF align=right>
 
<td width=33% bgcolor=#EEEEEF align=right>
<font size="+2">[[HowTo:Use_POV-Ray_with_Blender|Go To User's page ►]]</font></td></tr>
+
<font size="+2">[[HowTo:Use_POV-Ray_with_Blender|Перейти на сторінку користувача ►]]</font></td></tr>
 
</table>
 
</table>
 
<!--</wikinav>--->
 
<!--</wikinav>--->

Latest revision as of 14:03, 2 March 2025




▼ Сторінка розробника

POVExporterLogo.png
Перейти на сторінку користувача ►


Доповнення Blender до POV-Ray і навпаки (він же «POV@Ble») починалося як єдиний файл Python. Щоб бути сумісним із системою упаковки доповнень Blender, це доповнення мало:

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


bpy

У Blender є вбудований інтерпретатор Python, який завантажується під час запуску Blender і залишається активним, поки Blender працює. Цей інтерпретатор запускає сценарії для малювання інтерфейсу користувача, а також використовується для деяких внутрішніх інструментів Blender. Вбудований інтерпретатор Blender надає типове середовище Python, тому код із навчальних посібників про те, як писати сценарії Python, також можна запускати за допомогою інтерпретатора Blender. Blender надає свої Python модулі, такі як bpy і mathutils, для вбудованого інтерпретатора, щоб їх можна було імпортувати в сценарій і надати доступ до даних, класів і функцій Blender. Сценарії, які працюють з даними Blender, повинні будуть імпортувати модулі для роботи. Таким чином, з усіх модулів, якщо немає іншого, bpy зазвичай завжди імпортується в сценарії blender. (за винятком інтерактивної консолі, де це імпортування виконується автоматично для зручності)

Інтерактивна консоль Blender


Метадані надбудови

bl_info = {
 "name": "Стійкість зору",
 "автор": "Кемпбелл Бартон, "
 «Моріс Рейбо»,
 «Леонід Десятков»
 «Бастьєн Монтань»,
 «Константін Ран»
 «Сільвіо Фальчінеллі»,
 "версія": (0, 1, 1),
 "блендер": (2, 81, 0),
 "location": "Властивості візуалізації > Механізм візуалізації > Постійність зору",
 "description": "Постійність інтеграції Vision для blender",
 "doc_url": "{BLENDER_MANUAL_URL}/addons/render/povray.html",
 "category": "Відобразити",
 "warning": "В стадії активної розробки, шукає супроводжувач(ів)",
}


До Blender 4.2 загальна інформація про додаток визначалася в словнику з назвою

bl_info

Кожен «ключ» цього словника надавав Blender певну інформацію про додаток, хоча не всі були однаково важливими. Більшість інформації використовувалося в діалоговому вікні налаштувань користувача та допомагало користувачеві знайти та вибрати доповнення.

name

Тип кодової назви для надбудови, під якою вона згадується в джерелі Blender... (Назва інтерфейсу користувача може вказувати щось інше)

автор

Якщо ви зробите внесок, вам буде зараховано тут!

версія

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

блендер

Мінімальна версія Blender, необхідна для цього доповнення. Знову кортеж із трьох цілих чисел. Навіть якщо ви очікуєте, що все працюватиме зі старішою та новішою версіями, може бути гарною ідеєю вказати найранішу версію, з якою ви насправді тестували свій додаток! Розробка з чимось досить стабільним є важливою, а потім тестуйте з останньою версією безпосередньо перед фіксацією, але зазвичай не оновлюйте номер сумісної версії тоді, лише коли щось зламається на цьому етапі.

категорія

Категорія в налаштуваннях користувача, у якій згруповано наш додаток. Він працює з механізмами, сумісними з POV, які є рендерерами, тому історично було сенс додати його до категорії Render. На жаль, це не відображає багатоцільовий характер, який він зрештою вирощував (наприклад, доставлений імпортер, підсвічування синтаксису текстового редактора тощо...) Якщо можливо кілька категорій, можливо, нам слід додати їх.

місцезнаходження

Де знайти доповнення після його ввімкнення. Це може бути посилання на певну панель або внутрішній корпус, опис її розташування в меню.

опис

Короткий опис того, що робить додаток.

попередження

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

doc_url

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

tracker_url

Додаток POV, будучи частиною Blender, має власний запис трекера помилок, пов’язаний із ним, і цей ключ надасть вказівник на нього.

Коментарі

Однорядкові коментарі починаються з символу решетки (#), відразу після якого йде пробіл, і коментар починається з великої літери, але не закінчується крапкою. Їх можна додати після досить короткого рядка коду (залиште один порожній простір перед #).

Однією з вказівок щодо стилю форматування/кодування, яку слід використовувати, є [1], тому, наприклад, слід бути обережним, щоб рядки в тексті були достатньо короткими. файли сценаріїв менше 79 символів і менше 72 для рядків документації (див. нижче) або коментарів.

Періодично Blender Foundation перевіряє сценарії Blender на відповідність pep8. Допустима довжина рядка зрештою досягла 100 символів.

Якщо вам дійсно потрібно перевищити цей ліміт, наприклад, для тимчасових незавершених записок, будь ласка, додайте

# nopep8

в кінці відповідного рядка

Інші правила включають:

  • верблюжі шапки для імен класів: MyClass
  • усі назви модулів розділені нижніми літерами підкреслення: my_module
  • 4 відступи (без табуляції)
  • пробіли навколо математичних операторів: 1 + 1, а не 1+1
  • Використовуйте лише явний імпорт (ніколи не робіть імпорт *)
  • Не використовуйте один рядок для тесту та оператора, який залежить від нього: if val : body, натомість відокремте блоки операторів від умов, від яких вони залежать, принаймні 2 рядками.

Тоді як багаторядкові коментарі можуть починатися з потрійних лапок. Традиційним є використання трьох подвійних лапок для рядків документації, спеціального типу коментаря, який нічого не робить у програмі, але все одно з’являється, коли консоль використовується для отримання довідки щодо функції.

"""Це загальне пояснення"""

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

Функції

Функції визначаються за допомогою ключового слова 'def', після якого йде назва функції та пара круглих дужок. Коли функція посилається на переміщення та передачу її між файлами, вона більше не потребує дужок, але майже половину часу вони йдуть після назви функції, а між ними можна додатково вказати деякі атрибути.

Класи

Classes не лише дозволяють створювати визначення для повторного використання. Але це єдиний спосіб налаштувати елементи інтерфейсу користувача в Blender. Хороша новина полягає в тому, що це означає, що розробники аддонів фактично мають менше роботи. Жорстко закодована реалізація піклується про те, коли та які частини оновлювати автоматично для всіх елементів інтерфейсу користувача, а успадкування класів на вибір (API) гарантує, що ситуації можна обробляти оптимізованим способом. Деякі застарілі функції, такі як «draw()», мають бути перевизначені розробником надбудови, який переписує кожну відповідно до своїх потреб.

Щоб створити нові класи, використовуйте звичайний шаблон визначення класу, як показано в шаблонах Python у внутрішньому текстовому редакторі Blender... Або скопіюйте та вставте один з іншого місця сценарію.

Номенклатура класу

Наскільки можливо, дотримуйтеся того самого шаблону іменування, якого вимагає Blender Foundation: OT означає, що це оператор, MT — меню, PT — панель: Ім’я класу має бути складено таким чином: NAME_ADDON_PT_main_panel NOMDADDON - Великими літерами набираємо назву аддона. Підкреслення можна використовувати, якщо ім’я складається з кількох слів.

_PT_ – потім розділяється двома літерами, які позначають тип класу (від якого тип успадковується).

main_panel - використовуючи нижній регістр, ми можемо ввести назву оператора/панелі/заголовка тощо.

Інші типи класів:

HT – Заголовок
MT – Меню
ОТ – оператор
PT – панель
UL – список UI

Отже, оскільки ім’я аддона у нашому випадку POV, ось кілька прикладів дійсних імен класів та їхніх ідентифікаторів:

клас POV_MATERIAL_PT_replacement_field(bpy.types.Panel):
 bl_idname = 'pov_PT_replacement_field_panel'


клас POV_OT_add_basic(bpy.types.Operator):
 bl_idname = 'pov.addbasicitem'


клас POV_VIEW_MT_Basic_Items(bpy.types.Menu):
 bl_idname = 'pov_MT_basic_items_tools'

Помітили, як відрізняється ідентифікатор оператора? Нам не потрібно додавати "OT", а крапку. Нам також не потрібно додавати "_operator" в кінці.


API Blender Python дозволяє інтегрувати:


bpy.types.Panel
bpy.types.Menu
bpy.types.Operator
bpy.types.PropertyGroup
bpy.types.KeyingSet
bpy.types.RenderEngine

Це навмисно обмежено. Наразі для більш розширених функцій, таких як модифікатори сітки, типи об’єктів або вузли шейдерів, необхідно використовувати C/C++.

Для інтеграції Python Blender визначає методи, загальні для всіх типів. Це працює шляхом створення підкласу Python класу Blender, який містить змінні та функції, визначені батьківським класом, які попередньо визначені для взаємодії з Blender.

Зауважте, що ми створюємо підкласи члена bpy.types, це є спільним для всіх класів, які можна вбудувати в Blender і використовувати, щоб ми знали, чи це оператор, а не панель під час реєстрації.


Обидві властивості класу починаються з префікса bl_. Це умовне позначення, яке використовується для відмінності властивостей Blender від тих, які ви додаєте самі.

Оператори

Більшість надбудов визначають нові оператори, це класи, які реалізують певну функціональність. Фактичне визначення оператора має форму класу, похідного від bpy.types.Operator

імпорт bpy
клас MyTool(bpy.types.Operator):
 """Зробити щось з об'єктом"""
 bl_idname = "object.do_things_to_object"
 bl_label = "Виконувати дії з об'єктом"
 bl_options = {'РЕЄСТРАЦІЯ', 'СКАСУВАТИ'}

Рядок документації на початку визначення класу використовуватиметься як підказка скрізь, де цей оператор доступний, наприклад у меню, тоді як bl_label визначає фактичну мітку, яка використовується в самому пункті меню. Тут ми зберегли обидва однакові. Оператори будуть частиною даних Blender і зберігаються в модулі bpy.ops. Це bl_idname гарантує, що вхідні дані для цього оператора будуть називатися bpy.ops.object.move_object. Оператори зазвичай реєструються, щоб зробити їх придатними для використання, і це справді є недоліком bl_options. Однак, якщо ми також хочемо, щоб надбудова з’явилася в історії, щоб її можна було скасувати або повторити, нам потрібно додати UNDO до набору прапорців, призначеного для «bl_options», як тут.


Оператори мають обмеження, які можуть зробити їх написання втомливим.

Основні обмеження…

Неможливо передати такі дані, як об’єкти, сітки або матеріали для роботи (оператори використовують натомість контекст)

Повернене значення виклику оператора вказує на успіх (незалежно від того, завершено чи скасовано), у деяких випадках було б доцільніше з точки зору API повернути результат операції.

Функція 'poll()' для опитування операторів може вийти з ладу, якщо функція API викидає виняткову ситуацію, надаючи детальну інформацію про точну причину.

Функція execute()

Клас операторів може мати будь-яку кількість функцій-членів, але щоб бути корисним, він зазвичай повинен мати таку, яка перевизначає функцію 'execute()':

def execute(self, context):
 context.active_object.rotation.z += 33
 return {'FINISHED'}

Функція execute() отримує посилання на об’єкт context. Цей контекст містить, серед іншого, атрибут active_object, який вказує на активний об’єкт Blender. Кожен об’єкт у Blender має атрибут обертання, який є вектором із компонентами x, y та z. Змінити обертання об’єкта так само просто, як змінити один із цих компонентів, що саме ми робимо у рядку 2.

Функція execute() сигналізує про успішне виконання, повертаючи набір індикаторів, у цьому випадку набір, що складається лише з рядка "FINISHED".

Створення та додавання запису меню до реєстру

Коли ми ввімкнемо прапорець «Увімкнути надбудову» в «параметрах», Blender шукатиме функцію «'register()» і виконає її. Так само, коли вимикається надбудова, викликається функція unregister(). Отже, давайте використаємо їх як для реєстрації нашого оператора в Blender, так і для вставки пункту меню, який посилається на нашого оператора. скасувати підписку та скасувати його показ також важливо, щоб наш додаток не сприймався як інвазивний або руйнівний для попередньої конфігурації без шляху назад.

Щоб створити пункт меню, нам потрібно зробити дві речі:

  • Створіть функцію, яка створюватиме пункт меню
  • І додайте цю функцію до відповідного меню.

Зараз майже все в Blender доступне як об’єкт Python, і меню не є винятком. Ми хочемо додати наш запис до меню «Об’єкт» у 3D-перегляді, тому ми викликаємо

bpy.types.VIEW3D_MT_object.append()

і передаємо йому посилання на функцію, яку ми визначаємо

трохи нижче. Як ми знаємо ім'я цього об'єкта меню? Якщо ви позначили «Файл ⇒ Параметри користувача ⇒ Інтерфейс ⇒ Підказки Python», назва меню відображатиметься у підказці, коли ви наведете курсор на меню. На зображенні вище ми бачимо, що ми можемо використовувати bpy.types.VIEW3D_MT_object.append(), щоб додати щось до меню Object, тому що VIEW3D_MT_object потім відображається в тексті підказки, яка з’являється при наведенні курсора на це меню.

BlightBulb.png
Функція menu_func() сама по собі не виконує дію (це роль оператора)
Але під час виклику menu_func() додасть елемент інтерфейсу користувача, який вказує на об’єкт, переданий йому в параметрі self. Цей елемент інтерфейсу може змінювати користувач і, у свою чергу, взаємодіятиме з оператором.


Тут ми просто додамо введення оператора (тобто елемент, який виконуватиме наш оператор після натискання).

Аргумент self, переданий menu_func(), відноситься до меню.

У цьому меню є атрибут «layout» із функцією «operator()», якій ми передаємо назву нашого оператора. Це гарантує, що щоразу, коли користувач наводить курсор на меню Об'єкт, наш оператор буде відображатися в списку параметрів.

Назва нашого нового оператора MyTool міститься в його атрибуті bl_idname, тому ми передаємо MyTool.bl_idname.

Ім’я запису та його спливаюча підказка визначаються шляхом перегляду bl_label і docstring, визначених у нашому класі MyTool, а значок, що використовується в меню, визначається шляхом передачі додаткового параметра icon функції operator().

Визначення меню само по собі недостатньо, щоб зробити це меню придатним для використання. Щоб користувач міг знайти та використати його, нам потрібно додати меню до його батьківського елемента з функції register()' у кінці його файлу python.

def menu_func(self, context):
 self.layout.operator(MyTool.bl_idname, icon='MESH_CUBE')
def register():
 bpy.types.VIEW3D_MT_object.append(menu_func)
def unregister():
 bpy.types.VIEW3D_MT_object.remove(menu_func)

Оператори мають бути зареєстровані таким же чином, тому додавання зареєстрованого оператора до меню потребує двох-трьох окремих дій:

  • Оператор збереження;
  • потім додати його до існуючого меню;
  • Або спочатку збережіть щойно створене меню, до якого воно має належати, і лише потім додайте до нього оператор.

Лише після всього цього новий оператор з’явиться в інтерфейсі користувача, принаймні, якщо нічого іншого, натиснувши F3 у 3D вікні перегляду та ввівши мітку оператора

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

BlightBulb.png
Команди unregister() мають відображатися у зворотному порядку відповідних рядків register()
Це гарантує, що ви не спробуєте скасувати реєстрацію, наприклад, меню, яке було додано як дочірній елемент класу інтерфейсу користувача, який ви можете спробувати скасувати з реєстрації до цього дочірнього елемента, таким чином скасувавши реєстрацію чогось, чого вже немає... Це спричинить помилку та спричинить невдачу активації/деактивації доповнення.


Оптимізація

Зберігайте ваші «балові» оцінки мінімальними

Як і в багатьох об’єктно-орієнтованих мовах, Python дозволяє візуалізувати ієрархічну структуру з її рівнями, розділеними крапками (уявіть кожну крапку як отвір більшої російської ляльки ліворуч, що перекриває менші праворуч).

BlightBulb.png
Замініть непотрібно повторювані шляхи на псевдоніми
Оператор «крапка» — це простий спосіб отримати клас, дані, метод, будь-який об’єкт Python, включений у більшу ієрархію... Але майте на увазі, що це дорого, особливо якщо використовується в циклі.

Коли ми викликаємо

bpy.data.objects["my_obj"]

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

obj = bpy.data.objects["my_obj"]

Тож ви все ще можете використовувати його, лише керуючи розгалуженнями шляху до випадкових одноразових атрибутів, таких як e Приклад нижче:

obj.location.z += 1

для всіх інших атрибутів, доступних для ваших операцій читання або запису. Визначте якомога більше з цих обов’язкових псевдонімів перед входом у цикл, а не всередині нього. Уявіть, якби ваш GPS завжди показував вам попередні напрямки від початкової точки до наступних на кожному повороті!

Використовуйте «спробувати/крім» помірно

Оператор try корисний для економії часу під час написання коду перевірки помилок.

Однак «try» значно повільніше, ніж «if», оскільки кожного разу також має створюватися виняток, тому уникайте використання «try» у тих областях коду, які зациклюються та виконуються кілька разів.

Бувають випадки, коли використання «спробувати» є швидшим, ніж явне виявлення за допомогою тесту («якщо» чи іншим чином) складної умови, яка потенційно може спричинити помилку, тому варто поекспериментувати.


Хороший спосіб видалити деякі з ваших try ... окрім випадків, коли виявлена ​​помилка виявляється AttributeError, це замінити їх тестом вище за течією за допомогою функції hasattr():

for member in dir(properties_freestyle):
    subclass = getattr(properties_freestyle, member)
    try:
        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
    except:
        pass

міг тоді стати

for member in dir(properties_freestyle):
   subclass = getattr(properties_freestyle, member)
   if hasattr(subclass, "COMPAT_ENGINES"):
       subclass.COMPAT_ENGINES.add('POVRAY_RENDER')

Якщо вам потрібно використовувати try:... except:... не залишайте тип винятку невизначеним, це не дає жодного зворотного зв’язку чи читабельності коду. Натомість, якщо ви не знаєте, що це може бути, замініть його чимось, що дасть більше інформації під час фази налагодження:

("BaseException" знаходиться на вершині ієрархії винятків)

def your_function(b, c):
    try:
        a = b + c
        return True
    except BaseException as e:
        print(e.__doc__)
        print('An exception occurred: {}'.format(e))
        return False

Відокремте файли Python (*.py)

Історично сценарій був організований у пакет (кілька файлів у папці), використовуючи якомога менше файлів, щоб полегшити розуміння потоку даних. Спочатку було 3 основних файли:

  • __init__.py
  • ui.py
  • render.py

Однак деякі файли перевищували 10 000 рядків, що для такого доповнення було все одно занадто великим. Тому наразі допустимо, щоб найбільший файл залишався меншим за 2000 рядків. Цілком імовірно, що файли можуть трохи втратити вагу, якщо видалити застарілу підтримку 32-розрядної версії та модульувати частину коду в кілька функцій, які можна використовувати повторно. Ось поточні файли, які складають надбудову, і їхнє використання:

Ініціалізація

__init__.py

Створено налаштування користувача надбудови POV, дозволено користувачеві оновити надбудову до останньої версії та завантажено всі інші надбудови. (Зверніть увагу на подвійне підкреслення навколо імені файлу. Це робить його першим запущеним файлом) визначення «основного» блоку для пакету; Це також змушує Python розглядати певний каталог як пакет. Це одиниця, яка використовуватиметься під час виклику 'import render_povray' (а 'render_povray' — це каталог).

scenography_properties.py

Ініціалізуйте властивості для перекладу налаштувань камери/світла/оточення Blender на мову POV.

object_properties.py

Ініціалізація властивостей для перекладу параметрів об’єкта Blender на мову POV.

shading_properties.py

Ініціалізація властивостей для перекладу параметрів матеріалу Blender на мову POV.

texturing_properties.py

Ініціалізація властивостей для перекладу параметрів впливу текстур матеріалів, середовища (світу)... Blender на мову POV.

render_properties.py

Ініціалізація властивостей для перекладу параметрів візуалізації (з Blender, але особливо нативних з POV).

scripting_properties.py

Ініціалізація властивостей і полів для заповнення інструкцій безпосередньо мовою опису сцени POV.


Інтерфейс

Деякі зауваження, про які слід пам’ятати під час створення елементів інтерфейсу користувача:

Команди, надані Blender для інтерфейсу користувачає відносно простими. Оголошення інтерфейсу призначені для легкого створення прийнятного макета. Основне правило: якщо вам потрібно більше коду для макета інтерфейсу, ніж для самих властивостей, ви робите це неправильно.

Приклади інтерфейсу:

макет()

Основний макет — це простий макет Верхній -> Нижній.

layout.prop()
layout.prop()
layout.row()

Використовуйте row(), якщо потрібно мати більше однієї властивості в одному рядку.

рядок = layout.row()
row.prop()
row.prop()
layout.column()

Використовуйте column(), якщо ви хочете, щоб ваші властивості вирівнювалися зі стовпцем.

col = layout.column()
col.prop()
col.prop()
layout.split()

Це можна використовувати для створення складніших макетів. Наприклад, ви можете розділити макет і створити два макети column() поруч один з одним. Не використовуйте 'split()', якщо вам потрібні лише дві послідовні властивості. Використовуйте row() для цього.

split = layout.split()
col = split.column()
col.prop()
col.prop()
col = split.column()
col.prop()
col.prop()

Імена для оголошення:

Спробуйте використовувати лише такі імена змінних для оголошень інтерфейсу:

рядок для макета row().
col для макета column().
split для макета split().
потік для макета column_flow().
sub для вкладеного макета (наприклад, стовпець усередині стовпця)


base_ui.py

відображення робочого простору, натхненного програмним забезпеченням Moray, і визначення певних службових функцій. Завантаження всіх інших пов’язаних з графічним інтерфейсом модулів

scenography_gui.py)

Відображати властивості камери/світла/оточення з scenography_properties.py для редагування користувачем


object_gui.py :

Відображення властивостей об’єкта з object_properties.py для редагування користувачем


shading_gui.py

Відображення властивостей із shading_properties.py для редагування користувачем


shading_nodes.py

Переклад дерев вузлів у файл POV


texturing_gui.py

Відображення властивостей із texturing_properties.py для редагування користувачем


render_gui.py

Відображення властивостей з render_properties.py для редагування користувачем


scripting_gui.py

Показано властивості scripting_properties.py, щоб користувач міг додати власний код POV

Візуалізація / імпорт / редагування

render.py

Трансляція геометрії та різних властивостей інтерфейсу користувача (Blender та рідні POV) у файл POV


scenography.py

Трансляція властивостей камери, світла та середовища у відповідні функції POV


primitives.py

Відображення імпортованих або створених власних примітивів POV у 3D-виді для можливої ​​зміни перед рендерингом


object_mesh_topology.py

Переклад геометрії сітки в POV


object_curve_topology.py

Трансляція геометрій на основі векторних кривих у POV


object_particles.py

Переклад на POV об'єктів на основі симуляції частинок


shading.py

Переклад властивостей затінення як «текстур», оголошених у верхній частині файлу POV


texturing.py

Переклад впливів (модуляції растрового зображення) текстур на мову POV


df3_library.py

Відтворення диму через файли *.df3


scripting.py

Вставка елементів рідною мовою опису сцени POV, яка вставляється безпосередньо в експортований файл без необхідності відображати їх у Blender


update_files.py

Оновлено нові змінні з їхніх значень у старих версіях Blender API. Цей файл потрібно оновити

Попередні налаштування

Поряд із цими основними файлами також є деякі додаткові бібліотеки, які допомагають Blender протистояти іншим інтерфейсам, сумісним з Persistence of Vision, таким як povwin QTPOV або VSCode.

Матеріали (sss)

apple.py

chicken.py

cream.py

Ketchup.py

marble.py

potato.py

skim_milk.py

skin1.py

skin2.py

whole_milk.py

Опромінюваність

01_Debug.py

02_Fast.py

03_Normal.py

04_Two_Bounces.py

05_Final.py

06_Outdoor_Low_Quality.py

07_Outdoor_High_Quality.py

08_Outdoor(Sun)Light.py

09_Indoor_Low_Quality.py

10_Indoor_High_Quality.py

Навколишнє середовище

01_Clear_Blue_Sky.py

02_Partly_Hazy_Sky.py

03_Overcast_Sky.py

04_Cartoony_Sky.py

05_Under_Water.py

Люм'єр

01_(4800K)_Direct_Sun.py

02_(5400K)_High_Noon_Sun.py

03_(6000K)_Daylight_Window.py

04_(6000K)_2500W_HMI_(Halogen_Metal_Iodide).py

05_(4000K)_100W_Metal_Halide.py

06_(3200K)_100W_Quartz_Halogen.py

07_(2850K)_100w_Tungsten.py

08_(2600K)_40w_Tungsten.py

09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py

10_(4300K)_40W_Vintage_Fluorescent_T12.py

11_(5000K)_18W_Standard_Fluorescent_T8.py

12_(4200K)_18W_Cool_White_Fluorescent_T8.py

13_(3000K)_18W_Warm_Fluorescent_T8.py

14_(6500K)_54W_Grow_Light_Fluorescent_T5-HO.py

15_(3200K)_40W_Induction_Fluorescent.py

16_(2100K)_150W_High_Pressure_Sodium.py

17_(1700K)_135W_Low_Pressure_Sodium.py

18_(6800K)_175W_Mercury_Vapor.py

19_(5200K)_700W_Carbon_Arc.py

20_(6500K)_15W_LED_Spot.py

21_(2700K)_7W_OLED_Panel.py

22_(30000K)_40W_Black_Light_Fluorescent.py

23_(30000K)_40W_Black_Light_Bulb.py

24_(1850K)_Candle.py

шаблони

abyss.pov

biscuit.pov

bsp_Tango.pov

chess2.pov

cornell.pov

diffract.pov

diffuse_back.pov

float5

gamma_showcase.pov

grenadine.pov

isocacti.pov

mediasky.pov

patio-radio.pov

subsurface.pov wallstucco.pov

C++

Деякі області можуть отримувати функції POV лише за допомогою C++:

blender/editors/space_text/text_format_pov.c

blender/editors/space_text/text_format_ini.c

Mspace_text.c

Mtext_format.h

Mtext_format_ini.c

Mtext_format_pov.c

і файл MCMakelists.txt потрібно було змінити, щоб включити ці додані файли.


Але в Blender весь інтерфейс користувача написаний на Python, тому файл scripts/startup/bl_ui/space_text.py також було оновлено, хоча він знаходиться поза звичайними папками додатків:

# ##### BEGIN GPL LICENSE BLOCK #####
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####

# <pep8-80 compliant>
import bpy
from bpy.types import Header, Menu, Panel
from bpy.app.translations import pgettext_iface as iface_


class TEXT_HT_header(Header):
    bl_space_type = 'TEXT_EDITOR'

    def draw(self, context):
        layout = self.layout

        st = context.space_data
        text = st.text

        row = layout.row(align=True)
        row.template_header()

        TEXT_MT_editor_menus.draw_collapsible(context, layout)

        if text and text.is_modified:
            sub = row.row(align=True)
            sub.alert = True
            sub.operator("text.resolve_conflict", text="", icon='HELP')

        row = layout.row(align=True)
        row.template_ID(st, "text", new="text.new", unlink="text.unlink", open="text.open")

        row = layout.row(align=True)
        row.prop(st, "show_line_numbers", text="")
        row.prop(st, "show_word_wrap", text="")
        row.prop(st, "show_syntax_highlight", text="")

        if text:
            osl = text.name.endswith(".osl") or text.name.endswith(".oso")

            if osl:
                row = layout.row()
                row.operator("node.shader_script_update")
            else:
                row = layout.row()
                row.operator("text.run_script")

                row = layout.row()
                row.active = text.name.endswith(".py")
                row.prop(text, "use_module")

            row = layout.row()
            if text.filepath:
                if text.is_dirty:
                    row.label(text=iface_("File: *%r (unsaved)") %
                              text.filepath, translate=False)
                else:
                    row.label(text=iface_("File: %r") %
                              text.filepath, translate=False)
            else:
                row.label(text="Text: External"
                          if text.library
                          else "Text: Internal")


class TEXT_MT_editor_menus(Menu):
    bl_idname = "TEXT_MT_editor_menus"
    bl_label = ""

    def draw(self, context):
        self.draw_menus(self.layout, context)

    @staticmethod
    def draw_menus(layout, context):
        st = context.space_data
        text = st.text

        layout.menu("TEXT_MT_view")
        layout.menu("TEXT_MT_text")

        if text:
            layout.menu("TEXT_MT_edit")
            layout.menu("TEXT_MT_format")

        layout.menu("TEXT_MT_templates")


class TEXT_PT_properties(Panel):
    bl_space_type = 'TEXT_EDITOR'
    bl_region_type = 'UI'
    bl_label = "Properties"

    def draw(self, context):
        layout = self.layout

        st = context.space_data

        flow = layout.column_flow()
        flow.prop(st, "show_line_numbers")
        flow.prop(st, "show_word_wrap")
        flow.prop(st, "show_syntax_highlight")
        flow.prop(st, "show_line_highlight")
        flow.prop(st, "use_live_edit")

        flow = layout.column_flow()
        flow.prop(st, "font_size")
        flow.prop(st, "tab_width")

        text = st.text
        if text:
            flow.prop(text, "use_tabs_as_spaces")

        flow.prop(st, "show_margin")
        col = flow.column()
        col.active = st.show_margin
        col.prop(st, "margin_column")



class TEXT_PT_find(Panel):
    bl_space_type = 'TEXT_EDITOR'
    bl_region_type = 'UI'
    bl_label = "Find"

    def draw(self, context):
        layout = self.layout

        st = context.space_data



        #знайти
        col = layout.column(align=True)
        row = col.row(align=True)
        row.prop(st, "find_text", text="")
        row.operator("text.find_set_selected", text="", icon='TEXT')
        col.operator("text.find")

        # замінити
        col = layout.column(align=True)
        row = col.row(align=True)
        row.prop(st, "replace_text", text="")
        row.operator("text.replace_set_selected", text="", icon='TEXT')
        col.operator("text.replace")

        # налаштування
        layout.prop(st, "use_match_case")
        row = layout.row(align=True)
        row.prop(st, "use_find_wrap", text="Wrap")
        row.prop(st, "use_find_all", text="All")


class TEXT_MT_view(Menu):
    bl_label = "View"

    def draw(self, context):
        layout = self.layout

        layout.operator("text.properties", icon='MENU_PANEL')

        layout.separator()

        layout.operator("text.move",
                        text="Top of File",
                        ).type = 'FILE_TOP'
        layout.operator("text.move",
                        text="Bottom of File",
                        ).type = 'FILE_BOTTOM'

        layout.separator()

        layout.operator("screen.area_dupli")
        layout.operator("screen.screen_full_area")
        layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True


class TEXT_MT_text(Menu):
    bl_label = "Text"

    def draw(self, context):
        layout = self.layout

        st = context.space_data
        text = st.text

        layout.operator("text.new")
        layout.operator("text.open")

        if text:
            layout.operator("text.reload")

            layout.column()
            layout.operator("text.save")
            layout.operator("text.save_as")

            if text.filepath:
                layout.operator("text.make_internal")

            layout.column()
            layout.operator("text.run_script")


class TEXT_MT_templates_py(Menu):
    bl_label = "Python"

    def draw(self, context):
        self.path_menu(
            bpy.utils.script_paths("templates_py"),
            "text.open",
            props_default={"internal": True},
        )


class TEXT_MT_templates_osl(Menu):
    bl_label = "Open Shading Language"

    def draw(self, context):
        self.path_menu(
            bpy.utils.script_paths("templates_osl"),
            "text.open",
            props_default={"internal": True},
        )

class TEXT_MT_templates_pov(Menu):
    bl_label = "POV-Ray Scene Description Language"

    def draw(self, context):
        self.path_menu(
            bpy.utils.script_paths("templates_pov"),
            "text.open",
            props_default={"internal": True},
        )

class TEXT_MT_templates(Menu):
    bl_label = "Templates"

    def draw(self, context):
        layout = self.layout
        layout.menu("TEXT_MT_templates_py")
        layout.menu("TEXT_MT_templates_osl")
        layout.menu("TEXT_MT_templates_pov")


class TEXT_MT_edit_select(Menu):
    bl_label = "Select"

    def draw(self, context):
        layout = self.layout

        layout.operator("text.select_all")
        layout.operator("text.select_line")


class TEXT_MT_format(Menu):
    bl_label = "Format"

    def draw(self, context):
        layout = self.layout

        layout.operator("text.indent")
        layout.operator("text.unindent")

        layout.separator()

        layout.operator("text.comment")
        layout.operator("text.uncomment")

        layout.separator()

        layout.operator_menu_enum("text.convert_whitespace", "type")


class TEXT_MT_edit_to3d(Menu):
    bl_label = "Text To 3D Object"

    def draw(self, context):
        layout = self.layout

        layout.operator("text.to_3d_object",
                        text="One Object",
                        ).split_lines = False
        layout.operator("text.to_3d_object",
                        text="One Object Per Line",
                        ).split_lines = True


class TEXT_MT_edit(Menu):
    bl_label = "Edit"

    @classmethod
    def poll(cls, context):
        return (context.space_data.text)

    def draw(self, context):
        layout = self.layout

        layout.operator("ed.undo")
        layout.operator("ed.redo")

        layout.separator()

        layout.operator("text.cut")
        layout.operator("text.copy")
        layout.operator("text.paste")
        layout.operator("text.duplicate_line")

        layout.separator()

        layout.operator("text.move_lines",
                        text="Move line(s) up").direction = 'UP'
        layout.operator("text.move_lines",
                        text="Move line(s) down").direction = 'DOWN'

        layout.separator()

        layout.menu("TEXT_MT_edit_select")

        layout.separator()

        layout.operator("text.jump")
        layout.operator("text.start_find", text="Find...")
        layout.operator("text.autocomplete")

        layout.separator()

        layout.menu("TEXT_MT_edit_to3d")


class TEXT_MT_toolbox(Menu):
    bl_label = ""

    def draw(self, context):
        layout = self.layout

        layout.operator_context = 'INVOKE_DEFAULT'

        layout.operator("text.cut")
        layout.operator("text.copy")
        layout.operator("text.paste")

        layout.separator()

        layout.operator("text.run_script")


classes = (
    TEXT_HT_header,
    TEXT_MT_edit,
    TEXT_MT_editor_menus,
    TEXT_PT_properties,
    TEXT_PT_find,
    TEXT_MT_view,
    TEXT_MT_text,
    TEXT_MT_templates,
    TEXT_MT_templates_py,
    TEXT_MT_templates_osl,
    TEXT_MT_templates_pov,
    TEXT_MT_edit_select,
    TEXT_MT_format,
    TEXT_MT_edit_to3d,
    TEXT_MT_toolbox,
)


if __name__ == "__main__":  # лише для живого редагування.
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)

Слід зазначити, що спеціальний командний рядок

   # <pep8-80 compliant>

писав би pep-80 замість pep-8, тому що наближення до основного програмування Blender часто потребує більш вимогливих стандартів: pep-80 вимагає навіть меншої довжини рядка, тому файл, який проходить автоматизовані тести pep-80, які Blender Foundation регулярно проводить, може не пройти PEP-8.