Thomas Larsson - Введение в написание скриптов на Питоне для Блендера 2.5x. Примеры кода
bpy.types.Scene.MyInt = IntProperty(
name = "Integer",
description = "Enter an integer")
scn['MyInt'] = 17
bpy.types.Scene.MyFloat = FloatProperty(
name = "Float",
description = "Enter a float",
default = 33.33,
min = -100,
max = 100)
bpy.types.Scene.MyBool = BoolProperty(
name = "Boolean",
description = "True or False?")
scn['MyBool'] = True
bpy.types.Scene.MyEnum = EnumProperty(
items = [('Eine', 'Un', 'One'),
('Zwei', 'Deux', 'Two'),
('Drei', 'Trois', 'Three')],
name = "Ziffer")
scn['MyEnum'] = 2
bpy.types.Scene.MyString = StringProperty(
name = "String")
scn['MyString'] = "Lorem ipsum dolor sit amet"
return
initSceneProperties(bpy.context.scene)
#
# Меню в районе UI
#
class UIPanel(bpy.types.Panel):
bl_label = "Property panel"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
def draw(self, context):
layout = self.layout
scn = context.scene
layout.prop(scn, 'MyInt', icon='BLENDER', toggle=True)
layout.prop(scn, 'MyFloat')
layout.prop(scn, 'MyBool')
layout.prop(scn, 'MyEnum')
layout.prop(scn, 'MyString')
layout.operator("idname_must.be_all_lowercase_and_contain_one_dot")
#
# Кнопка выводит значения свойств в окне консоли.
#
class OBJECT_OT_PrintPropsButton(bpy.types.Operator):
bl_idname = "idname_must.be_all_lowercase_and_contain_one_dot"
bl_label = "Print props"
def execute(self, context):
scn = context.scene printProp("Int: ", 'MyInt', scn)
printProp("Float: ", 'MyFloat', scn)
printProp("Bool: ", 'MyBool', scn)
printProp("Enum: ", 'MyEnum', scn)
printProp("String: ", 'MyString', scn)
return{'FINISHED'}
def printProp(label, key, scn):
try:
val = scn[key]
except:
val = 'Undefined'
print("%s %s" % (key, val))
# Регистрация
bpy.utils.register_module(__name__)
Опрос (Polling)
Скрипт часто работает только в некоторых конкретных условиях, например, когда активен объект правильного типа. Например, скрипт, который манипулирует вершинами меша, не может делать что-либо значимое, если активный объект — арматура.
Эта программа добавляет панель, которая модифицирует материал активного объекта. Панель находится в секции интерфейса пользователя (открывается с помощью N), но она видима, только если активным объектом является меш по крайней мере с одним материалом. Проверка, сколько материалов имеет активный объект, делается через poll(). Это не функция, а скорее метод класса, указанный с помощью команды @classmethod выше определения. Так в чем же разница между функцией и методом класса? Не спрашивайте меня! Все, что я знаю, что со строкой @classmethod код работает, а без неё нет.
Ну, с точки зрения программирования на Питоне действие этого декоратора хорошо объяснили здесь python.su/forum, а вот почему объявленный метод класса с именем poll влияет на поведение элементов интерфейса в Блендере, я так и не понял — прим. пер.
#----------------------------------------------------------
# File poll.py
#----------------------------------------------------------
import bpy, random
#
# Меню в районе UI
#
class ColorPanel(bpy.types.Panel):
bl_label = "Modify colors"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
@classmethod
def poll(self, context):
if context.object and context.object.type == 'MESH':
return len(context.object.data.materials)
def draw(self, context):
layout = self.layout
scn = context.scene
layout.operator("random.button")
layout.operator("darken_random.button")
layout.operator("invert.button")
#
# Три кнопки
#
class RandomButton(bpy.types.Operator):
bl_idname = "random.button"
bl_label = "Randomize"
def execute(self, context):
mat = context.object.data.materials[0]
for i in range(3):
mat.diffuse_color[i] = random.random()
return{'FINISHED'}
class DarkenRandomButton(bpy.types.Operator):
bl_idname = "darken_random.button"
bl_label = "Darken Randomly"
def execute(self, context):
mat = context.object.data.materials[0]
for i in range(3):
mat.diffuse_color[i] *= random.random()
return{'FINISHED'}
class InvertButton(bpy.types.Operator):
bl_idname = "invert.button"
bl_label = "Invert"
def execute(self, context):
mat = context.object.data.materials[0]
for i in range(3):
mat.diffuse_color[i] = 1 - mat.diffuse_color[i]
return{'FINISHED'}
# Регистрация
bpy.utils.register_module(__name__)
Динамическое выпадающее меню
Эта программа добавляет панель с выпадающим меню на панели интерфейса пользователя. В начале меню содержит три пункта: красный, зеленый и синий. Есть две кнопки, помеченные Set color (Задать цвет). Верхняя изменяет цвет активного объекта на цвет, выбранный в выпадающем меню, а нижняя устанавливает цвет, определенный тремя движками. Цвета можно добавлять в выпадающее меню и удалять их из него.
Также заметьте, что с тем же успехом работает опрос для кнопок; кнопка Set color становится серой, если активный объект не является мешем с по крайней мере одним материалом.
#----------------------------------------------------------
# File swatches.py
#----------------------------------------------------------
import bpy
from bpy.props import *
theSwatches = [
("1 0 0" , "Red" , "1 0 0"),
("0 1 0" , "Green" , "0 1 0"),
("0 0 1" , "Blue" , "0 0 1")]
def setSwatches():
global theSwatches
bpy.types.Object.my_swatch = EnumProperty(
items = theSwatches,
name = "Swatch")
setSwatches()
bpy.types.Object.my_red = FloatProperty(
name = "Red", default = 0.5,
min = 0, max = 1)
bpy.types.Object.my_green = FloatProperty(
name = "Green", default = 0.5,
min = 0, max = 1)
bpy.types.Object.my_blue = FloatProperty(
name = "Blue", default = 0.5,
min = 0, max = 1)
def findSwatch(key):
for n,swatch in enumerate(theSwatches):
(key1, name, colors) = swatch
if key == key1:
return n
raise NameError("Unrecognized key %s" % key)
# Панель образцов
class SwatchPanel(bpy.types.Panel):
bl_label = "Swatches"
#bl_idname = "myPanelID"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "material"
def draw(self , context):
layout = self.layout
ob = context.active_object
layout.prop_menu_enum(ob, "my_swatch")
layout.operator("swatches.set").swatch=True
layout.separator()
layout.prop(ob, "my_red")
layout.prop(ob, "my_green")
layout.prop(ob, "my_blue")
layout.operator("swatches.set").swatch=False
layout.operator("swatches.add")
layout.operator("swatches.delete")
# Установка кнопки
class OBJECT_OT_SetButton(bpy.types.Operator):
bl_idname = "swatches.set"
bl_label = "Set color"
swatch = bpy.props.BoolProperty()
@classmethod
def poll(self, context):
if context.object and context.object.type == 'MESH':
return len(context.object.data.materials)
def execute(self, context):
global theSwatches
ob = context.object
if self.swatch:
n = findSwatch(ob.my_swatch)
(key, name, colors) = theSwatches[n]
words = colors.split()
color = (float(words[0]), float(words[1]), float(words[2]))
else:
color = (ob.my_red, ob.my_green, ob.my_blue)
ob.data.materials[0].diffuse_color = color
return{'FINISHED'}
# Добавление кнопки
class OBJECT_OT_AddButton(bpy.types.Operator):
bl_idname = "swatches.add"
bl_label = "Add swatch"
def execute(self, context):
global theSwatches
ob = context.object
colors = "%.2f %.2f %.2f" % (ob.my_red, ob.my_green, ob.my_blue)
theSwatches.append((colors, colors, colors))
setSwatches()
return{'FINISHED'}