В API последней версии Blender 2.8 разработчики внесли множество изменений, поэтому практически все скрипты и аддоны, написанные для более ранних версий Blender (2.7 и ниже), перестали работать. Для того, чтобы пользоваться полюбившимися аддонами в новой версии Blender, их нужно портировать – исправить их код для корректной работы с новым API Blender.
Изменения, которые необходимо внести в код аддона, чтобы он заработал в Blender 2.80:
- В Blender версии 2.7 и ниже использовалась версия интерпретатора Python 3.5.3 и ниже. В Blender 2.8 используется Python версии 3.7.0. Разработчикам аддонов стоит обновить интерпретатор Python, установленный в системе до нужной версии.
- В инициализующей секции описания – в файле __init__.py или в заголовке аддона в словаре bl_info обязательно нужно указывать версию Blender 2.80. Это изменение нужно сделать абсолютно всем разработчикам. Аддоны с указанной более низкой версией в Blender 2.8 не запустятся.
Правильный код выглядит так:
1 2 3 |
bl_info = { 'blender': (2, 80, 0) } |
- Если в коде аддона определены операторы, у которых есть свойства (параметры), их инициализация должна описываться не знаком “=”, а знаком “:”. Это обусловлено спецификацией Python PEP8, которой следует Blender. Эти изменения также придется вносить в свой код всем разработчикам без исключений.
Если эти изменения не внесены, Blender при вызове такого оператора сигнализирует ошибкой:
class .. contains a properties which should be an annotation!
Пример кода для корректного определения свойства оператора:
1 2 3 |
class_prop: BoolProperty( default=False ) |
- Т-панель в Blender 2.8 больше не используется для размещения пользовательского интерфейса UI. Если в аддоне есть интерфейс, размещенный в T-панели, Blender сигнализирует ошибкой:
Registering panel class … has category …
Теперь интерфейс пользователя размещается в N-панели, поэтому в описании класса панели в параметре bl_region_type вместо значения “TOOLS” необходимо указывать “UI”.
Пример правильного кода:
1 2 3 4 5 6 7 8 9 |
class MyPanel(Panel): bl_idname = 'panel.my_panel' bl_label = 'MY_PANEL' bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'MY_PANEL' def draw(self, context): ... |
- При вызове функций с передаваемыми параметрами, в Blender 2.8 нельзя указывать неименованные параметры. Аргументы функции обязательно должны передаваться в виде “имя_аргумента=значение_аргумента”. Это изменение затрагивает всех разработчиков и связано опять же со следованием спецификации PEP.
Если происходит вызов функции без указания именованного аргумента, Blender сигнализирует ошибкой:
…operator(): required parameter “…” to be a keyword argument!
Пример правильного указания параметра (наличие text= обязательно):
1 |
self.layout.label(text='Hello World!') |
- Обращение к активной сцене – теперь получить активную сцену через bpy.context.screen.scene нельзя. При попытке такого обращения Blender сигнализирует ошибкой:
AttributeError: ‘screen’ object has no attribute ‘scene’
Обращение к активной сцене тепер осуществляется через объект window.
Пример правильного обращения к активной сцене:
1 |
active_scene = bpy.context.window.scene |
- Обращение к активном объекту в Blender 2.8 осуществляется только через context, обращаться через scene.objects.active больше нельзя. Это связано с введением коллекций.
При попытке обращения к активному объекту через объект сцены Blender сигнализирует ошибкой:
AttributeError: ‘bpy_prop_collection’ object has no attribute ‘active’
Пример правильного обращения к активному мешу:
1 |
active_object = bpy.context.active_object |
- Источники света в Blender 2.8 теперь имеют тип ‘LIGHT’ и в секции data размещаются соответственно в списке ‘lights’.
При попытке обратиться к списку источников света через bpy.data.lamps, как раньше, Blender сигнализирует ошибкой:
AttributeError: ‘BlendData’ object has no attribute ‘lamps’
Пример правильного обращения к источникам света:
1 2 |
bpy.data.lights # <bpy_collection[1], BlendDataLights> |
- Обращение к свойствам пользователя заменено с “user_preferences” на “preferences”.
При попытке обращения к свойствам пользователя через “bpy.context.user_preferences” Blender сигнализирует ошибкой:
AttributeError: ‘Context’ object has no attribute ‘user_preferences’
Пример правильного обращения к свойствам пользователя:
1 |
bpy.context.preferences |
- Внутренние иконки операторов в Blender 2.8 были переработаны, некоторые иконки были убраны, некоторые добавлены, некоторые сменили идентификатор.
При использовании в вызовах операторов иконок с некорректными идентификаторами, например
1 |
layout.operator('my_ops.my_operator', icon='ZOOMIN') |
Blender сигнализирует ошибкой:
TypeError: UILayout.operator(): Error with keyword argument “icon” – enum “ZOOM” not found in {…
Для проверки идентификаторов доступных иконок можно воспользоваться встроенным аддоном “Icon Viewer”.
- Из доступных для обработки из аддона событий убраны события обновления сцены “scene_update_post” и “scene_update_pre” и теперь на эти события невозможно повесить собственные обработчики. Соответственно, в Blender 2.8 теперь отсутствует возможность вызова пользовательской функции при обновлении сцены.
При попытке подписать обработчик на событие обновления сцены Blender сигнализирует ошибкой:
AttributeError: ‘bpy.app_handlers’ object has no attribute ‘scene_update_post’
Как результат такого изменения – пропала возможность обойти ошибку вида ACCESS VIOLATION при различного вида пакетных («батч- ») операциях, например при пакетном рендере можно было взывать рендер со следующей камеры не сразу после завершения рендера с предыдущей (Blender падает с ошибкой), а после обновления сцены (ошибки не происходило).
Одно из возможных решений – использовать вместо обработки события обновления сцены таймеры, но это решение уже не так красиво.
Пример использования таймера для вызова последующего рендера, после завершения предыдущего:
1 2 3 4 5 6 7 8 9 |
if not bpy.app.timers.is_registered(render_next): bpy.app.timers.register(render_next, first_interval=3.0) # call render_next after 3 sek def render_next(): rez = bpy.ops.render.render() if rez == {'CANCELLED'}: return 3.0 # retry after more 3 sec else: return None |