BlenderУкраина
Главная
Новости
Статьи
Уроки
Файлы
Ссылки
Форум
Галерея
Конкурсы
• Поиск по сайту


Логин:

Пароль:

 Запомнить
Восстановление пароля

Зарегистрироваться

Наше сообщество:

 Форум

 Галерея
       Все работы по рейтингу
       Все новые работы
       Последние комментарии

 Конкурсы
       Ежедневный
       На баннер (прием работ)
       Повтори
       Художественный
       Модель для сборки

 Гостевая

 Радио

RSSНовости Blender
Последние сообщения форума

 Добавить новость
парфюмерияпарфюмерия : Днепропетровск : модели радиомоделирадиомодели модели на радиоуправлении
Сейчас на сайте 57 посетителей:
DbI4A, Иван П., alber, fd, Кузнец, f1ackee, antikiller, newman, INFILNTRATOR, SATtva, ExeQt0r, jstas, Илья Джордан, Маг, miniguru, MageasteR, CineMay, Alex-hg, n752, Александр туз, GameR, hikkikamori, kotov, Uruk, ПыщПыщ, INFERNAL, Morthan, XDev и 29 гостей

Обсуждаемые темы:

Вопросы новичков и ответы (newman)
Blender 2.5 Materials and Textures Cookbook (n752)
Свои фото (MageasteR)
Игра "Fast Shot" (miniguru)
Просто BGE работы (INFILNTRATOR)
kenprol WIP (SATtva)
Дни рождения и прочие поздравлялки. :) (Илья Джордан)
Ежедневный Конкурс моделирования в Blender (ПыщПыщ)
Анекдоты (Реалист)
WIP`ы от sanyasamsonov (sanyasamsonov)
Вопрос(ы) по созданию игр (Серый 3d волк)
Текстурирование и рендеринг робота (Alex00Z)
Blender 2.63 для 3Ds Max'еров и Unity3D - пользователей (vknw123)
Болталка (boris1029)
SOS!помогите пожалуйста (aoz)
Lux Render (sanyasamsonov)

Работа дня:

Лариска-крыска
Ежедневный конкурс моделирования

Новые работы в галерее:


Автор: Sever

Автор: zloy_tux

Автор: shader211


Автоматический полив


Лекарственные травы


Прически и стрижки  

::Содержание::

Аддоны Блендера



До сих пор мы рассматривали только автономные скрипты, которые выполняются из окна текстового редактора. Для конечных пользователей более удобно, если скрипт - это аддон (add-on, надстройка) Блендера, который может быть включен в окне Пользовательских настроек. Также можно автоматически загружать скрипт каждый раз при запуске Блендера

Для того, чтобы скрипт был аддоном, он должен быть написан по-особому. Там должна быть структура bl_info в начале файла, а также в конце должны быть определены функции register (регистрации) и unregister (отмены регистрации). Кроме того, скрипт должен быть размещен в месте, в котором Блендер ищет аддоны при запуске. Оно включает в себя каталоги addons и addons-contrib , которые расположены в подкаталоге 2.57/scripts каталога, в котором находится Блендер.

Прикрепление ключей формы



Этот скрипт может быть выполнен, как обычно, из окна текстового редактора. Тем не менее, он также может быть доступен как аддон Блендера. Информация аддона указывается в словаре bl_info в начале файла.
bl_info = {
    'name': 'Shapekey pinning',
    'author': 'Thomas Larsson',
    'version': (0, 1, 2),
    'blender': (2, 5, 7),
    'api': 35774,
    "location": "View3D > UI panel > Shapekey pinning",
    'description': 'Pin and key the shapekeys of a mesh',
    'warning': '',
    'wiki_url': 'http://blenderartists.org/forum/showthread.php?193908',
    'tracker_url': '',
    "support": 'COMMUNITY',
    "category": "3D View"}

Смысл большинства ключей в этом словаре очевиден.

• name: Название аддона.
• author: Имя автора.
• version: Версия скрипта.
• blender: Версия Блендера.
• api: Номер ревизии, с которой скрипт работает.
• location: Где искать кнопки.
• description: Описание, отображаемое в виде всплывающей подсказки и в документации.
• warning: Предупреждающее сообщение. Если не пусто, в окне пользовательских настроек будет отображаться небольшой предупреждающий знак.
• wiki_url: Ссылка на вики-страницу скрипта. Должна быть реальным Блендер-сайтом, но здесь мы ссылаемся на тему в форуме blenderartists.org.
• tracker_url: Ссылка на трекер ошибок скрипта.
• support: Официальная поддержка или сообщество
• category: Категория скрипта, т.е. 3D View, Import-Export, Add Mesh, или Rigging. Соответствует категориям в окне Пользовательских настроек.
Многие элементы могут быть просто опущены, как мы увидим в других примерах ниже.

Второе требование к аддону - это определение функций register() и unregister() которые обычно располагаются в конце файла. register() обычно вызывает оператор bpy.utils.register_module(__name__), в котором регистрируются все классы, определенные в файле. Она также может содержать несколько пользовательских задач инициализации. Скрипт этого примера также объявляет пользовательские RNA-свойства. Как мы видели в разделе RNA-свойства против ID-свойств, объявление необходимо здесь потому, что в противном случае логическое свойство будет отображаться как целое число.
def register():
initialize()
bpy.utils.register_module(__name__)

def unregister():
bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
register()

Отмена регистрации аналогична регистрации. Последние строки делают возможным запуск скрипта в автономном режиме из окна Текстового редактора. Даже если пользователь никогда не будет выполнять скрипт из редактора, полезно иметь такую ​​возможность при отладке.

Скопируйте файл в место, где Блендер ищет аддоны. Перезагрузите Блендер. Откройте окно Пользовательских настроек из меню File » User Preferences, и перейдите во вкладку Add-ons. Наш скрипт можно найти в нижней части раздела 3D View.

Мы узнаём поля из словаря bl_info . Включите скрипт, нажав флажок в правом верхнем углу. Если вы хотите, чтобы аддон загружался каждый раз при запуске Блендера, нажмите кнопку Save As Default в нижней части окна.

После включения аддона, он появляется в UI-панели.

Сам скрипт отображает ключи формы активного объекта на панели интерфейса. Куб по умолчанию не имеет ключей формы. Вместо него мы импортируем персонаж MakeHuman, имеющий множество выражений лица, которые реализуются через ключи формы. MakeHuman - это приложение, которое легко позволяет вам конструировать персонаж. Полностью оснащённый и текстурированный персонаж может быть экспортирован в Блендер использованием формата MHX (MakeHuman eXchange). MHX-файлы могут быть импортированы в Блендер с помощью импортера MHX, аддона, который распространяется с Блендером.

Что имеет значение для настоящего примера, это что меш MakeHuman имеет множество ключей формы. Если вы нажмёте кнопку Pin (прикрепить) справа от значения ключа формы, ключ формы будет закреплен, то есть его значение станет равным единице, в то время как значения всех остальных ключей формы будут равны нулю. Если кнопка Autokey на временной шкале нажата, будет добавлен ключ на значение ключа формы. Если к тому же включена опция Key all, ключи добавляются для каждого ключа формы меша.

#----------------------------------------------------------
# File shapekey_pin.py
#----------------------------------------------------------
 
bl_info = {
    'name': 'Shapekey pinning',
    'author': 'Thomas Larsson',
    'version': '(0, 1, 2)',
    'blender': (2, 5, 7),
    "location": "View3D > UI panel > Shapekey pinning",
    'description': 'Pin and key the shapekeys of a mesh',
    'warning': '',
    'wiki_url': 'http://blenderartists.org/forum/showthread.php?193908',
    'tracker_url': '',
    "support": 'COMMUNITY',
     "category": "3D View"}
 
import bpy
from bpy.props import *
 
#
#    class VIEW3D_OT_ResetExpressionsButton(bpy.types.Operator):
#
class VIEW3D_OT_ResetExpressionsButton(bpy.types.Operator):
    bl_idname = "shapepin.reset_expressions"
    bl_label = "Reset expressions"
 
    def execute(self, context):
        keys = context.object.data.shape_keys
        if keys:
            for shape in keys.keys:
                shape.value = 0.0
        return{'FINISHED'}    
 
#
#    class VIEW3D_OT_PinExpressionButton(bpy.types.Operator):
#
 
class VIEW3D_OT_PinExpressionButton(bpy.types.Operator):
    bl_idname = "shapepin.pin_expression"
    bl_label = "Pin"
    expression = bpy.props.StringProperty()
 
    def execute(self, context):
        skeys = context.object.data.shape_keys
        if skeys:
            frame = context.scene.frame_current
            for block in skeys.key_blocks:            
                oldvalue = block.value
                block.value = 1.0 if block.name == self.expression else 0.0
                if (context.tool_settings.use_keyframe_insert_auto and 
                    (context.scene.key_all or 
                    (block.value > 0.01) or 
                    (abs(block.value-oldvalue) > 0.01))):
                    block.keyframe_insert("value", index=-1, frame=frame)
        return{'FINISHED'}    
 
#
#    class ExpressionsPanel(bpy.types.Panel):
#
 
class ExpressionsPanel(bpy.types.Panel):
    bl_label = "Pin shapekeys"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
 
    @classmethod
    def poll(cls, context):
        return context.object and (context.object.type == 'MESH')
 
    def draw(self, context):
        layout = self.layout
        layout.operator("shapepin.reset_expressions")
        layout.prop(context.scene, "key_all")
        skeys = context.object.data.shape_keys
        if skeys:
            for block in skeys.key_blocks:            
                row = layout.split(0.75)
                row.prop(block, 'value', text=block.name)
                row.operator("shapepin.pin_expression", 
                    text="Pin").expression = block.name
        return
 
#
#    инициализация и регистрация
#
 
def initialize():
    bpy.types.Scene.key_all = BoolProperty(
        name="Key all",
        description="Set keys for all shapes",
        default=False)
 
def register():
    initialize()
    bpy.utils.register_module(__name__)
 
def unregister():
    bpy.utils.unregister_module(__name__)
 
if __name__ == "__main__":
    register()

Простой импорт BVH-файлов



BVH формат обычно используется для передачи анимации персонажей, например, от данных захвата движения (mocap). Эта программа простого импортера BVH, которая строит скелет с действием (action), описанный в файле BVH. Он реализован в виде аддона Блендера со словарём bl_info в верхней части файла и кодом регистрации в конце.

После выполнения скрипта или включения его в качестве аддона, простой импортер BVH может быть вызван из панели пользовательского интерфейса (CtrlN). Есть две опции: логическая переменная с информацией о том, повернуть ли меш на 90 градусов (чтобы направить Z вверх), и масштаб.

Эта программа также показывает, как вызвать диалог выбора файлов, нажав кнопку на панели. Класс кнопки Load BVH наследуется от двух базовых классов bpy.types.Operator и ImportHelper.
class OBJECT_OT_LoadBvhButton(bpy.types.Operator, ImportHelper):

Класс ImportHelper (возможно, недокументированный) определяет некоторые атрибуты, которые используются для фильтрации файлов, отображающихся в диалоге выбора файлов.

filename_ext = ".bvh"
filter_glob = bpy.props.StringProperty(default="*.bvh", options={'HIDDEN'})
filepath = bpy.props.StringProperty(name="File Path",
maxlen=1024, default="")

Существует аналогичный класс ExportHelper, который ограничивает имеющийся выбор файлов экспорта.

#----------------------------------------------------------
# File simple_bvh_import.py
# Simple bvh importer
#----------------------------------------------------------
 
bl_info = {
    'name': 'Simple BVH importer (.bvh)',
    'author': 'Thomas Larsson',
    'version': (1, 0, 0),
    'blender': (2, 5, 7),
    'api': 34786,
    'location': "File > Import",
    'description': 'Simple import of Biovision bvh',
    'category': 'Import-Export'}
 
import bpy, os, math, mathutils, time
from mathutils import Vector, Matrix
from io_utils import ImportHelper
 
#
#    class CNode:
#
 
class CNode:
    def __init__(self, words, parent):
        name = words[1]
        for word in words[2:]:
            name += ' '+word
 
        self.name = name
        self.parent = parent
        self.children = []
        self.head = Vector((0,0,0))
        self.offset = Vector((0,0,0))
        if parent:
            parent.children.append(self)
        self.channels = []
        self.matrix = None
        self.inverse = None
        return
 
    def __repr__(self):
        return "CNode %s" % (self.name)
 
    def display(self, pad):
        vec = self.offset
        if vec.length < Epsilon:
            c = '*'
        else:
            c = ' '
        print("%s%s%10s (%8.3f %8.3f %8.3f)" % 
            (c, pad, self.name, vec[0], vec[1], vec[2]))
        for child in self.children:
            child.display(pad+"  ")
        return
 
    def build(self, amt, orig, parent):
        self.head = orig + self.offset
        if not self.children:
            return self.head
 
        zero = (self.offset.length < Epsilon)
        eb = amt.edit_bones.new(self.name)        
        if parent:
            eb.parent = parent
        eb.head = self.head
        tails = Vector((0,0,0))
        for child in self.children:
            tails += child.build(amt, self.head, eb)
        n = len(self.children)
        eb.tail = tails/n
        (trans,quat,scale) = eb.matrix.decompose()
        self.matrix = quat.to_matrix()
        self.inverse = self.matrix.copy()
        self.inverse.invert()
        if zero:
            return eb.tail
        else:        
            return eb.head
 
#
#    readBvhFile(context, filepath, rot90, scale):
#
 
Location = 1
Rotation = 2
Hierarchy = 1
Motion = 2
Frames = 3
 
Deg2Rad = math.pi/180
Epsilon = 1e-5
 
def readBvhFile(context, filepath, rot90, scale):
    fileName = os.path.realpath(os.path.expanduser(filepath))
    (shortName, ext) = os.path.splitext(fileName)
    if ext.lower() != ".bvh":
        raise NameError("Not a bvh file: " + fileName)
    print( "Loading BVH file "+ fileName )
 
    time1 = time.clock()
    level = 0
    nErrors = 0
    scn = context.scene
 
    fp = open(fileName, "rU")
    print( "Reading skeleton" )
    lineNo = 0
    for line in fp: 
        words= line.split()
        lineNo += 1
        if len(words) == 0:
            continue
        key = words[0].upper()
        if key == 'HIERARCHY':
            status = Hierarchy
        elif key == 'MOTION':
            if level != 0:
                raise NameError("Tokenizer out of kilter %d" % level)    
            amt = bpy.data.armatures.new("BvhAmt")
            rig = bpy.data.objects.new("BvhRig", amt)
            scn.objects.link(rig)
            scn.objects.active = rig
            bpy.ops.object.mode_set(mode='EDIT')
            root.build(amt, Vector((0,0,0)), None)
            #root.display('')
            bpy.ops.object.mode_set(mode='OBJECT')
            status = Motion
        elif status == Hierarchy:
            if key == 'ROOT':    
                node = CNode(words, None)
                root = node
                nodes = [root]
            elif key == 'JOINT':
                node = CNode(words, node)
                nodes.append(node)
            elif key == 'OFFSET':
                (x,y,z) = (float(words[1]), float(words[2]), float(words[3]))
                if rot90:                    
                    node.offset = scale*Vector((x,-z,y))
                else:
                    node.offset = scale*Vector((x,y,z))
            elif key == 'END':
                node = CNode(words, node)
            elif key == 'CHANNELS':
                oldmode = None
                for word in words[2:]:
                    if rot90:
                        (index, mode, sign) = channelZup(word)
                    else:
                        (index, mode, sign) = channelYup(word)
                    if mode != oldmode:
                        indices = []
                        node.channels.append((mode, indices))
                        oldmode = mode
                    indices.append((index, sign))
            elif key == '{':
                level += 1
            elif key == '}':
                level -= 1
                node = node.parent
            else:
                raise NameError("Did not expect %s" % words[0])
        elif status == Motion:
            if key == 'FRAMES:':
                nFrames = int(words[1])
            elif key == 'FRAME' and words[1].upper() == 'TIME:':
                frameTime = float(words[2])
                frameTime = 1
                status = Frames
                frame = 0
                t = 0
                bpy.ops.object.mode_set(mode='POSE')
                pbones = rig.pose.bones
                for pb in pbones:
                    pb.rotation_mode = 'QUATERNION'
        elif status == Frames:
            addFrame(words, frame, nodes, pbones, scale)
            t += frameTime
            frame += 1
 
    fp.close()
    time2 = time.clock()
    print("Bvh file loaded in %.3f s" % (time2-time1))
    return rig
 
#
#    channelYup(word):
#    channelZup(word):
#
 
def channelYup(word):
    if word == 'Xrotation':
        return ('X', Rotation, +1)
    elif word == 'Yrotation':
        return ('Y', Rotation, +1)
    elif word == 'Zrotation':
        return ('Z', Rotation, +1)
    elif word == 'Xposition':
        return (0, Location, +1)
    elif word == 'Yposition':
        return (1, Location, +1)
    elif word == 'Zposition':
        return (2, Location, +1)
 
def channelZup(word):
    if word == 'Xrotation':
        return ('X', Rotation, +1)
    elif word == 'Yrotation':
        return ('Z', Rotation, +1)
    elif word == 'Zrotation':
        return ('Y', Rotation, -1)
    elif word == 'Xposition':
        return (0, Location, +1)
    elif word == 'Yposition':
        return (2, Location, +1)
    elif word == 'Zposition':
        return (1, Location, -1)
 
#
#    addFrame(words, frame, nodes, pbones, scale):
#
 
def addFrame(words, frame, nodes, pbones, scale):
    m = 0
    for node in nodes:
        name = node.name
        try:
            pb = pbones[name]
        except:
            pb = None
        if pb:
            for (mode, indices) in node.channels:
                if mode == Location:
                    vec = Vector((0,0,0))
                    for (index, sign) in indices:
                        vec[index] = sign*float(words[m])
                        m += 1
                    pb.location = (scale * vec  - node.head) * node.inverse
                    for n in range(3):
                        pb.keyframe_insert('location', index=n, frame=frame, group=name)
                elif mode == Rotation:
                    mats = []
                    for (axis, sign) in indices:
                        angle = sign*float(words[m])*Deg2Rad
                        mats.append(Matrix.Rotation(angle, 3, axis))
                        m += 1
                    mat = node.inverse * mats[0] * mats[1] * mats[2] * node.matrix
                    pb.rotation_quaternion = mat.to_quaternion()
                    for n in range(4):
                        pb.keyframe_insert('rotation_quaternion',
                                           index=n, frame=frame, group=name)
    return
 
#
#    initSceneProperties(scn):
#
 
def initSceneProperties(scn):
    bpy.types.Scene.MyBvhRot90 = bpy.props.BoolProperty(
        name="Rotate 90 degrees", 
        description="Rotate the armature to make Z point up")
    scn['MyBvhRot90'] = True
 
    bpy.types.Scene.MyBvhScale = bpy.props.FloatProperty(
        name="Scale", 
        default = 1.0,
        min = 0.01,
        max = 100)
    scn['MyBvhScale'] = 1.0
 
initSceneProperties(bpy.context.scene)
 
#
#    class BvhImportPanel(bpy.types.Panel):
#
 
class BvhImportPanel(bpy.types.Panel):
    bl_label = "BVH import"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
 
    def draw(self, context):
        self.layout.prop(context.scene, "MyBvhRot90")
        self.layout.prop(context.scene, "MyBvhScale")
        self.layout.operator("simple_bvh.load")
 
#
#    class OBJECT_OT_LoadBvhButton(bpy.types.Operator, ImportHelper):
#
 
class OBJECT_OT_LoadBvhButton(bpy.types.Operator, ImportHelper):
    bl_idname = "simple_bvh.load"
    bl_label = "Load BVH file (.bvh)"
 
    # From ImportHelper. Filter filenames.
    filename_ext = ".bvh"
    filter_glob = bpy.props.StringProperty(default="*.bvh", options={'HIDDEN'})
 
    filepath = bpy.props.StringProperty(name="File Path", 
        maxlen=1024, default="")
 
    def execute(self, context):
        import bpy, os
        readBvhFile(context, self.properties.filepath, 
            context.scene.MyBvhRot90, context.scene.MyBvhScale)
        return{'FINISHED'}    
 
    def invoke(self, context, event):
        context.window_manager.fileselect_add(self)
        return {'RUNNING_MODAL'}    
 
#
#    Registration
#
 
def menu_func(self, context):
    self.layout.operator("simple_bvh.load", text="Simple BVH (.bvh)...")
 
def register():
    bpy.utils.register_module(__name__)
    bpy.types.INFO_MT_file_import.append(menu_func)
 
def unregister():
    bpy.utils.unregister_module(__name__)
    bpy.types.INFO_MT_file_import.remove(menu_func)
 
if __name__ == "__main__":
    try:
        unregister()
    except:
        pass
    register()

::Содержание::
© 2007-2012 Юлия Корбут, некоторые права соблюдены.
© 2007-2012 Julia Korbut, some rights reserved.