Свойства (Properties)

RNA-свойства против ID-свойств

В Блендере есть два различных типа свойств: ID-свойства и RNA-свойства. RNA-свойства расширяют определение структуры данных. Они должны быть объявлены до того, как будут использоваться.


Я потратил некоторое время на выяснение того, как же расшифровывается и что означает аббревиатура RNA для программирования на Питоне в Блендере. Может быть, я был недостаточно настойчив в поисках, но всё, что я нашел — это РНК, Рибонуклеиновая кислота. Разработчики применили химико-биологическую метафору для обозначения реальных структур данных на языке С (DNA, в переводе ДНК) и соответствующих им структур на Питоне (RNA, в переводе РНК). С понятием ID, думаю все и так знакомы, это сокращение слова Идентификатор. - прим. пер.


bpy.types.Object.myRnaInt = bpy.props.IntProperty(

   name = "RNA int",

   min = -100,

   max = 100,

   default = 33)

Как только RNA-свойства были объявлены, они будут доступны через точечный синтаксис:

cube.myRnaInt = -99

После декларации RNA-свойства myRnaInt расширяет определение структуры данных Object, каждый объект будет иметь это свойство.

ID-cвойство добавляется к единственному блоку данных, не влияя на другие данные того же самого типа. Ему не нужна какая-либо предварительная декларация, но оно автоматически определяется при присвоении, напр.

cube.data["MyIdInt"] = 4711

ID-свойства могут только быть целыми, вещественными, и строками; другие типы автоматически будут преобразованы. Следовательно, строка

cube.data["MyIdBool"] = True

определяет целое ID-свойство, а не логическое.


Не знаю, как в предыдущих версиях, а в 2.57 вполне можно определять списки — прим. пер.


Свойства сохраняются в blend-файле, но декларации свойств — нет.


Вот скрипт, который создает три меша, назначает различные свойства и печатает их величины в консоли.


#---------------------------------------------------------- 

# File properties.py 

#---------------------------------------------------------- 

import bpy 

from bpy.props import *


# Очистка сцены и создание нескольких объектов 

bpy.ops.object.select_by_type(type='MESH') 

bpy.ops.object.delete() 

bpy.ops.mesh.primitive_cube_add(location=(-3,0,0)) 

cube = bpy.context.object 

bpy.ops.mesh.primitive_cylinder_add(location=(0,0,0)) 

cyl = bpy.context.object 

bpy.ops.mesh.primitive_uv_sphere_add(location=(3,0,0)) 

sphere = bpy.context.object


# Определение RNA-свойства для каждого объекта 

bpy.types.Object.myRnaInt = IntProperty(

   name = "RNA int",

   min = -100, max = 100,

   default = 33)  


bpy.types.Object.myRnaFloat = FloatProperty(

   name = "RNA float",

   default = 12.345,

   min = 1, max = 20)  


bpy.types.Object.myRnaString = StringProperty(

   name = "RNA string",

   default = "Ribonucleic acid")  


bpy.types.Object.myRnaBool = BoolProperty(

   name = "RNA bool")  


bpy.types.Object.myRnaEnum = EnumProperty(

   items = [('one', 'eins', 'un'),

         ('two', 'zwei', 'deux'),

        ('three', 'drei', 'trois')],

   name = "RNA enum")


# Присвоение RNA-свойств кубу 

cube.myRnaInt = -99 

cube.myRnaFloat = -1 

cube.myRnaString = "I am an RNA prop" 

cube.myRnaBool = True 

cube.myRnaEnum = 'three'


# Создание ID-свойств для меша куба присвоением значений. 

cube.data["MyIdInt"] = 4711 

cube.data["MyIdFloat"] = 666.777 

cube.data["MyIdString"] = "I am an ID prop" 

cube.data["MyIdBool"] = True


# Печать всех свойств 

def printProp(rna, path):

   try:

      print('  %s%s =' % (rna.name, path), eval("rna"+path))

   except:

      print('  %s%s does not exist' % (rna.name, path))


for ob in [cube, cyl, sphere]:

   print("%s RNA properties" % ob)

   printProp(ob, ".myRnaInt")

   printProp(ob, ".myRnaFloat")

   printProp(ob, ".myRnaString")

   printProp(ob, ".myRnaBool")

   printProp(ob, ".myRnaEnum")

   print("%s ID properties" % ob.data)

   printProp(ob.data, '["MyIdInt"]')

   printProp(ob.data, '["MyIdFloat"]')

   printProp(ob.data, '["MyIdString"]')

   printProp(ob.data, '["MyIdBool"]')


Скрипт напечатает следующий результат на консоль:


 RNA properties Cube.myRnaInt = -99

   Cube.myRnaFloat = 1.0

   Cube.myRnaString = I am an RNA prop

   Cube.myRnaBool = True

   Cube.myRnaEnum = three 

 ID properties

   Cube.001["MyIdInt"] = 4711

   Cube.001["MyIdFloat"] = 666.777

   Cube.001["MyIdString"] = I am an ID prop

   Cube.001["MyIdBool"] = 1 

 RNA properties

   Cylinder.myRnaInt = 33

   Cylinder.myRnaFloat = 12.345000267028809

   Cylinder.myRnaString = Ribonucleic acid

   Cylinder.myRnaBool = False

   Cylinder.myRnaEnum = one

 ID properties

   Cylinder["MyIdInt"] does not exist

   Cylinder["MyIdFloat"] does not exist

   Cylinder["MyIdString"] does not exist

   Cylinder["MyIdBool"] does not exist 

 RNA properties

   Sphere.myRnaInt = 33 Sphere.myRnaFloat = 12.345000267028809

   Sphere.myRnaString = Ribonucleic acid

   Sphere.myRnaBool = False

   Sphere.myRnaEnum = one

 ID properties

   Sphere["MyIdInt"] does not exist

   Sphere["MyIdFloat"] does not exist

   Sphere["MyIdString"] does not exist

   Sphere["MyIdBool"] does not exist



Все три объекта имеют RNA-свойства, поскольку они являются расширением типа данных Object. RNA-свойствам Куба программой присвоены значения, кроме значения myRnaFloat, которое не может быть меньше чем 1. Цилиндру и сфере никаких свойств присвоено не было, но они все равно имеют RNA-свойства со значением по умолчанию.

Мешу куба программой были заданы ID-свойства. Заметьте, что свойство MyIdBool является целочисленной 1, а не логической True.

Свойства Объекта отображаются в панели пользовательского интерфейса под Properties, и также в контексте объекта. Свойства меша можно найти в контексте меша.




Как мы видели в распечатке, мы можем иметь доступ к RNA-свойствам объекта сферы. Тем не менее, они не появляются в интерфейсе пользователя. Очевидно, только присвоенные значения свойств сохраняются в блоке данных Объекта. Мы можем использовать RNA-свойство, которое не присвоено в скрипте; при этом берется значение по умолчанию. В противовес этому, если мы попытаемся получить доступ к незаданному ID-свойству, будет возбуждена ошибка.




Свойства совместимы со связями файлов. Сохраните blend-файл и привяжите (link) куб в новый файл. Как RNA-, так и ID-свойства появляются в новом файле, но они серые, поскольку они не могут быть доступны в связанном файле.



Если мы проксим (proxify) связанный куб, свойства объекта принадлежат блоку данных прокси-объекта, и могут быть модифицированы в связанном файле. В противовес этому, свойства меша принадлежат блоку данных меша и не могут изменяться.



Как упомянуто выше, свойства сохранены в blend-файлах, но декларации свойств — нет. Закройте и перезапустите Блендер и откройте файл, который мы сохранили выше. Свойства myRnaBool и myRnaEnum окажутся преобразованными в целые. Фактически, они и были сохранены как целые всё время, но отображались как логические и перечисления из-за продекларированных свойств, сохранённых в типе данных Object.

Чтобы подтвердить, что RNA-свойства превратились в ID-свойства, выполните следующий скрипт.


#---------------------------------------------------------- 

# File print_props.py 

#---------------------------------------------------------- 

import bpy  


def printProp(rna, path):

   try:

      print('  %s%s =' % (rna.name, path), eval("rna"+path))

   except:

      print('  %s%s does not exist' % (rna.name, path)) 


ob = bpy.context.object print("%s RNA properties" % ob) 

printProp(ob, ".myRnaInt") 

printProp(ob, ".myRnaFloat") 

printProp(ob, ".myRnaString") 

printProp(ob, ".myRnaBool") 

printProp(ob, ".myRnaEnum") 

print("%s ID properties" % ob) 

printProp(ob, '["myRnaInt"]') 

printProp(ob, '["myRnaFloat"]') 

printProp(ob, '["myRnaString"]') 

printProp(ob, '["myRnaBool"]') 

printProp(ob, '["myRnaEnum"]') 

print("%s ID properties" % ob.data) 

printProp(ob.data, '["MyIdInt"]') 

printProp(ob.data, '["MyIdFloat"]') 

printProp(ob.data, '["MyIdString"]') 

printProp(ob.data, '["MyIdBool"]')


Этот скрипт выведет следующий текст на терминале.


RNA properties

   Cube.myRnaInt does not exist

   Cube.myRnaFloat does not exist

   Cube.myRnaString does not exist

   Cube.myRnaBool does not exist

   Cube.myRnaEnum does not exist 

 ID properties

   Cube["myRnaInt"] = -99

   Cube["myRnaFloat"] = 1.0

   Cube["myRnaString"] = I am an RNA prop

   Cube["myRnaBool"] = 1

   Cube["myRnaEnum"] = 2 

 ID properties

   Cube.001["MyIdInt"] = 4711

   Cube.001["MyIdFloat"] = 666.777

   Cube.001["MyIdString"] = I am an ID prop

   Cube.001["MyIdBool"] = 1


Если мы восстановим декларации свойств, ID-свойства преобразуются обратно в RNA-свойства.


Вращение костей

Эта программа ожидает, что активный объект — это арматура. Она сохраняет угол вращения каждой editbone как свойство соответствующей кости, и в конце выводит величины свойств на терминале. При выполнении с выбранной арматурой на изображении ниже, результат на терминале выглядит следующим образом.

Head 3.1416 

Arm_L 1.5708 

Leg_R -2.7646 

Leg_L 2.7646 

Arm_R -1.5708 

Torso 3.1416

Заметьте, что величины свойств выражены в радианах. В интерфейсе углы отображаются в градусах, но при доступе из Питона они выражены в радианах. Тем не менее, свойство Roll - это просто некоторая вещественная переменная, и Блендер не знает, что его предполагается использовать как угол.

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



Этот код действительно несколько полезен для скрипта, который перенастраивает данные, полученные от захвата движения (motion capture). Для того, чтобы делать это правильно, нам нужно знать углы поворота roll. Тем не менее, их нельзя получить, если арматура связана с другим файлом через прокси. Для того, чтобы получить доступ к углу поворота rig.data.edit_bones[name].roll, арматуру нужно переключить в режим редактирования, который не доступен для связанных объектов. Но если скрипт выполнен в файле, где арматура определена, свойство Roll может быть доступно из связанного файла как rig.pose.bones[name].bone["Roll"].


#---------------------------------------------------------- 

# File bone_roll.py 

#---------------------------------------------------------- 

import bpy  


def createBoneRollProps(rig):

   if rig.type != 'ARMATURE':

     raise NameError("Object not an armature")

     # Объект не является арматурой

   bpy.context.scene.objects.active = rig

   try:

     bpy.ops.object.mode_set(mode='EDIT')

     editable = (len(rig.data.edit_bones) > 0)

   except:

     editable = False


   rolls = {}

   if editable:

     for eb in rig.data.edit_bones:

        rolls[eb.name] = eb.roll

     bpy.ops.object.mode_set(mode='POSE')

     for pb in rig.pose.bones:

       pb.bone["Roll"] = rolls[pb.name]

   else:

     try:

        bpy.ops.object.mode_set(mode='POSE')

     except:

       raise NameError("Armature is not posable. Create proxy")

       # У арматуры не доступно позирование. Создайте прокси

     for pb in rig.pose.bones:

       try:

        rolls[pb.name] = pb.bone["Roll"]

       except:

         raise NameError("Create roll props in asset file")

         # Создайте свойство roll в файле актива

   return rolls  


rolls = createBoneRollProps(bpy.context.object) 

for (bname, roll) in rolls.items():

     print("  %16s %8.4f" % (bname, roll))



Загрузка...