API Blender предоставляет для использования набор простых типов свойств, описанных в bpy.props (IntProperty, BoolProperty и т.д.). Но базовых типов не всегда хватает, иногда нужны более сложные. API Blender позволяет группировать простые свойства, создавая таким образом более сложные.
Рассмотрим создание такого свойства на примере матрицы 3х3.
Сначала опишем класс со структурой создаваемого свойства.
Матрицу 3х3 можно представить, как комбинацию трех векторов, следовательно мы можем использовать три свойства FloatVectorProperty чтобы описать матрицу:
1 2 3 4 5 6 7 8 9 10 11 12 |
from bpy.types import PropertyGroup class Matrix3x3_property(PropertyGroup): row0: FloatVectorProperty( default=(1.0, 0.0, 0.0) ) row1: FloatVectorProperty( default=(0.0, 1.0, 0.0) ) row2: FloatVectorProperty( default=(0.0, 0.0, 1.0) ) |
Класс созданного кастомного свойства нужно зарегистрировать в функциях register и очистить в unregister.
1 2 3 4 5 6 7 8 |
from bpy.utils import register_class, unregister_class def register(): register_class(Matrix3x3_property) def unregister(): unregister_class(Matrix3x3_property) |
Для того, чтобы присвоить созданное свойство с матрицей какому-либо объекту (мешу), нужно создать указатель на него. Сделаем это также в функции register и удалим в unregister.
1 2 3 4 5 6 7 8 |
from bpy.types import Mesh def register(): Mesh.matrix_prop = PointerProperty(type=Matrix3x3_property) def unregister(): del Mesh.matrix_prop |
Объединим все вместе:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
from bpy.props import PointerProperty, FloatVectorProperty from bpy.types import PropertyGroup, Mesh from bpy.utils import register_class, unregister_class class Matrix3x3_property(PropertyGroup): row0: FloatVectorProperty( default=(1.0, 0.0, 0.0) ) row1: FloatVectorProperty( default=(0.0, 1.0, 0.0) ) row2: FloatVectorProperty( default=(0.0, 0.0, 1.0) ) def register(): register_class(Matrix3x3_property) Mesh.matrix_prop = PointerProperty(type=Matrix3x3_property) def unregister(): del Mesh.matrix_prop unregister_class(Matrix3x3_property) |
Мы придали каждому мешу свойство matrix_prop, к которому теперь можем обращаться в любой момент. Например, чтобы получить значение первого элемента первой строки матрицы:
1 2 |
bpy.context.object.data.matrix_prop.row0[0] # 1.0 |
Однако, чтобы получить всю матрицу, такое обращение неудобно. Добавим к классу созданного нами свойства Matrix3x3_property геттер и сеттер для удобного присваивания/получения его значения.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@property def matrix(self): return ( (self.row0[0], self.row0[1], self.row0[2]), (self.row1[0], self.row1[1], self.row1[2]), (self.row2[0], self.row2[1], self.row2[2]) ) @matrix.setter def matrix(self, matrix3x3): self.row0 = matrix3x3[0] self.row1 = matrix3x3[1] self.row2 = matrix3x3[2] |
Теперь мы можем назначать или получать значения свойства в удобном виде.
Задание значения:
1 |
bpy.context.object.data.matrix_prop.matrix = ((1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0)) |
и получение:
1 2 |
bpy.context.object.data.matrix_prop.matrix # ((1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0)) |
Также можно определить функцию __repr__ для удобной печати значения.
1 2 |
def __repr__(self): return '({0},{1},{2}), ({3},{4},{5}), ({6},{7},{8})'.format(self.row0[0], self.row0[1], self.row0[2], self.row1[0], self.row1[1], self.row1[2], self.row2[0], self.row2[1], self.row2[2]) |
1 2 |
bpy.context.object.data.matrix_prop # (1.0,1.0,1.0), (2.0,2.0,2.0), (3.0,3.0,3.0) |
Итоговый код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
from bpy.props import PointerProperty, FloatVectorProperty from bpy.types import PropertyGroup, Mesh from bpy.utils import register_class, unregister_class class Matrix3x3_property(PropertyGroup): row0: FloatVectorProperty( default=(1.0, 0.0, 0.0) ) row1: FloatVectorProperty( default=(0.0, 1.0, 0.0) ) row2: FloatVectorProperty( default=(0.0, 0.0, 1.0) ) def __repr__(self): return '({0},{1},{2}), ({3},{4},{5}), ({6},{7},{8})'.format(self.row0[0], self.row0[1], self.row0[2], self.row1[0], self.row1[1], self.row1[2], self.row2[0], self.row2[1], self.row2[2]) @property def matrix(self): return ( (self.row0[0], self.row0[1], self.row0[2]), (self.row1[0], self.row1[1], self.row1[2]), (self.row2[0], self.row2[1], self.row2[2]) ) @matrix.setter def matrix(self, matrix3x3): self.row0 = matrix3x3[0] self.row1 = matrix3x3[1] self.row2 = matrix3x3[2] def register(): register_class(Matrix3x3_property) Mesh.matrix_prop = PointerProperty(type=Matrix3x3_property) def unregister(): del Mesh.matrix_prop unregister_class(Matrix3x3_property) |