Литвек - электронная библиотека >> Thomas Larsson >> Python и др. >> Введение в написание скриптов на Питоне для Блендера 2.5x. Примеры кода >> страница 3
программа создаёт арматуру.


Введение в написание скриптов на Питоне для Блендера 2.5x. Примеры кода. Иллюстрация № 9
#---------------------------------------------------

# File armature.py

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

import bpy, math

from mathutils import Vector, Matrix


def createRig(name, origin, boneTable):

    # Создание арматуры и объекта

    bpy.ops.object.add(

        type='ARMATURE',

        enter_editmode=True,

        location=origin)

    ob = bpy.context.object

    ob.show_x_ray = True

    ob.name = name

    amt = ob.data

    amt.name = name+'Amt'

    amt.show_axes = True


    # Создание костей

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

    for (bname, pname, vector) in boneTable:

        bone = amt.edit_bones.new(bname)

        if pname:

            parent = amt.edit_bones[pname]

            bone.parent = parent

            bone.head = parent.tail

            bone.use_connect = False

            (trans, rot, scale) = parent.matrix.decompose()

        else:

            bone.head = (0,0,0)

            rot = Matrix.Translation((0,0,0)) # Матрица идентичности

        bone.tail = Vector(vector) * rot + bone.head

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

    return ob


def poseRig(ob, poseTable):

    bpy.context.scene.objects.active = ob

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

    deg2rad = 2*math.pi/360


    for (bname, axis, angle) in poseTable:

        pbone = ob.pose.bones[bname]

        # Установка режима вращения в Euler XYZ (Эйлерово),

        # легче для понимания, чем кватернионы по-умолчанию

        pbone.rotation_mode = 'XYZ'

        # Косяк в документации: Euler.rotate(angle,axis):

        # оси в ['x','y','z'] а не ['X','Y','Z']

        pbone.rotation_euler.rotate_axis(axis, angle*deg2rad)

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

    return


def run(origo):

    origin = Vector(origo)

    # Таблица костей в форме (кость, родитель, вектор)

    # Вектор дан в локальных координатах

    boneTable1 = [

        ('Base', None, (1,0,0)),

        ('Mid', 'Base', (1,0,0)),

        ('Tip', 'Mid', (0,0,1))

    ]

    bent = createRig('Bent', origin, boneTable1)


    # Вторая оснастка является прямой линией, то есть кости проходят вдоль локальной оси Y

    boneTable2 = [

        ('Base', None, (1,0,0)),

        ('Mid', 'Base', (0,0.5,0)),

        ('Mid2', 'Mid', (0,0.5,0)),

        ('Tip', 'Mid2', (0,1,0))

    ]

    straight = createRig('Straight', origin+Vector((0,2,0)), boneTable2)


    # Поза второй остнастки

    poseTable2 = [

        ('Base', 'X', 90),

        ('Mid2', 'Z', 45),

        ('Tip', 'Y', -45)

    ]

    poseRig(straight, poseTable2)


    # Поза первой остнастки

    poseTable1 = [

        ('Tip', 'Y', 45),

        ('Mid', 'Y', 45),

        ('Base', 'Y', 45)

    ]

    poseRig(bent, poseTable1)

    return


if __name__ == "__main__":

    run((0,5,0))


Меш с оснасткой
Эта программа добавляет арматуру и меш. Арматура имеет три кости (Base (базовая), Mid (средняя), Tip (конечная)) и ограничения:

1. Ограничение IK Mid -> Tip.

2. Ограничение Stretch To Mid -> Tip.

3. Ограничение Copy Rotation Base -> Tip.

Меш деформируется арматурой. Следовательно, создаются модификатор арматуры и соответствующие группы вершин.


Введение в написание скриптов на Питоне для Блендера 2.5x. Примеры кода. Иллюстрация № 10
#----------------------------------------------------------

# File rigged_mesh.py

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

import bpy, mathutils


def createArmature(origin):

    # Создание арматуры и объекта

    amt = bpy.data.armatures.new('MyRigData')

    rig = bpy.data.objects.new('MyRig', amt)

    rig.location = origin

    rig.show_x_ray = True amt.show_names = True

    # Привязка объекта к сцене

    scn = bpy.context.scene

    scn.objects.link(rig)

    scn.objects.active = rig scn.update()


    # Создание костей

#next two lines by PKHG SVN 36504 W32

    bpy.ops.object.editmode_toggle()

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

#original does not work??!! bpy.ops.object.mode_set(mode='EDIT')

    base = amt.edit_bones.new('Base')

    base.head = (0,0,0)

    base.tail = (0,0,1)


    mid = amt.edit_bones.new('Mid')

    mid.head = (0,0,1)

    mid.tail = (0,0,2)

    mid.parent = base

    mid.use_connect = True


    tip = amt.edit_bones.new('Tip')

    tip.head = (0,0,2)

    tip.tail = (0,0,3)


    # Ограничения костей. Арматура должна быть в режиме позы.

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


    # Ограничение IK Mid -> Tip

    pMid = rig.pose.bones['Mid']

    cns1 = pMid.constraints.new('IK')

    cns1.name = 'Ik'

    cns1.target = rig

    cns1.subtarget = 'Tip'

    cns1.chain_count = 1


    # Ограничение StretchTo Mid -> Tip с влиянием 0.5

    cns2 = pMid.constraints.new('STRETCH_TO')

    cns2.name = 'Stretchy'

    cns2.target = rig

    cns2.subtarget = 'Tip'

    cns2.influence = 0.5

    cns2.keep_axis = 'PLANE_X'

    cns2.volume = 'VOLUME_XZX'


    # Ограничение Copy rotation Base -> Tip

    pBase = rig.pose.bones['Base']

    cns3 = pBase.constraints.new('COPY_ROTATION')

    cns3.name = 'Copy_Rotation'

    cns3.target = rig

    cns3.subtarget = 'Tip'

    cns3.owner_space = 'WORLD'

    cns3.target_space = 'WORLD'


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

    return rig


def createMesh(origin):

    # Создание меша и объекта

    me = bpy.data.meshes.new('Mesh')

    ob = bpy.data.objects.new('MeshObject', me)

    ob.location = origin

    # Привязка объекта к сцене

    scn = bpy.context.scene

    scn.objects.link(ob)

    scn.objects.active = ob

    scn.update()


    # Список координат вершин.

    verts = [

        (0.5, 0.5,0), (0.5,-0.5,0), (-0.5,-0.5,0), (-0.5,0.5,0),

        (0.5,0.5,1), (0.5,-0.5,1), (-0.5,-0.5,1), (-0.5,0.5,1),

        (-0.5,0.5,2), (-0.5,-0.5,2), (0.5,-0.5,2), (0.5,0.5,2),

        (0.5,0.5,3), (0.5,-0.5,3), (-0.5,-0.5,3), (-0.5, 0.5,3)

    ]

    # Список граней.

    faces = [

        (0, 1, 2, 3),

        (0, 4, 5, 1),

        (1, 5, 6, 2),

        (2, 6, 7, 3),

        (4, 0, 3, 7),

        (4, 7, 8, 11),

        (7, 6, 9, 8),

        (6, 5, 10, 9),

        (5, 4, 11, 10),

        (10, 11, 12, 13),

        (9, 10, 13, 14),

        (8, 9, 14, 15),

        (11, 8, 15, 12),

        (12, 15, 14, 13)

    ]


    # Создание меша из передаваемых списков вершин, рёбер, граней.

    # Или рёбра или грани должны быть [], иначе Вам нужны проблемы

    me.from_pydata(verts, [], faces)


    # Обновление меша с новыми данными

    me.update(calc_edges=True)

    return ob


def skinMesh(ob, rig):

    # Списки вершин в группах, в форме (вершина, вес)

    vgroups = {}

    vgroups['Base'] = [

        (0, 1.0), (1, 1.0), (2, 1.0), (3, 1.0),

        (4, 0.5), (5, 0.5), (6, 0.5), (7, 0.5)]

    vgroups['Mid'] = [

        (4, 0.5), (5, 0.5), (6, 0.5), (7, 0.5),

        (8, 1.0), (9, 1.0), (10, 1.0), (11, 1.0)]

    vgroups['Tip'] = [(12, 1.0), (13, 1.0), (14, 1.0), (15, 1.0)]


    # Создание групп вершин и добавление вершин и весов

    # Первый аргумент в назначении — список, чтобы можно

    # было назначать несколько вершин сразу

    for name in vgroups.keys():

        grp = ob.vertex_groups.new(name)

        for (v, w) in vgroups[name]:

            grp.add([v], w, 'REPLACE')


    # Добавление меш-объекту модификатора арматуры, с использованием

    # групп вершин, а не envelopes

    mod = ob.modifiers.new('MyRigModif', 'ARMATURE')

    mod.object = rig mod.use_bone_envelopes = False

    mod.use_vertex_groups = True


    return


def run(origin):

    rig = createArmature(origin)

    ob = createMesh(origin)

    skinMesh(ob, rig)


    # Перемещение и вращение кости Tip в режиме позы

    bpy.context.scene.objects.active = rig

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

    ptip = rig.pose.bones['Tip']

    ptip.location = (0.2,-0.5,0)

    rotMatrix = mathutils.Matrix.Rotation(0.6, 3, 'X')

    ptip.rotation_quaternion = rotMatrix.to_quaternion()


    return


if