Шрифт:
Интервал:
Закладка:
Кости позиционируются в арматуре определением позиций их головы и хвоста (тупой и острый концы соответственно, в представлении кости как восьмиугольника). Для соединения костей не достаточно сделать позицию хвоста одной кости равной позиции головы другой. Для того, чтобы кость следовала за перемещениями другой кости, она должна быть дочерней к ней. Отношения родитель-потомок осуществляются установкой в атрибут parent потомка ссылки на объект родительской кости. В нашем примере, у нас каждая кость ладони является потомком своей соответствующей кости руки.
Кости в составе арматуры индексируются их именем. Если свойство модификатора арматуры VGROUPS установлено, имя кости должно быть идентично имени группы вершин, на которую она влияет.
Последняя строка кода нашего примера также важна; необходимо сделать арматуру родителем Меш-объекта. Это может показаться излишним в ситуациях, где арматура и меш остаются в одном и том же месте, и перемешаются только отдельные кости в арматуре; но если не сделать этого, это приведёт к неустойчивому отображению меша при интерактивном изменении позы (Вы должны переводить меш в режим редактирования и обратно, например, чтобы видеть эффект от позы на арматуре, который полностью непригоден для работы). Результат нашей оснастки будет выглядеть похожим на это (мы установили режим отображения арматуры в x-ray, чтобы сделать её видимой через меш):
Отрендеренный результат выглядит так:
Мы могли бы захотеть ограничить движение отдельных костей до точных вращений вокруг оси z, и это можно сделать добавлением ограничений (constraints). Мы столкнемся с ограничениями в следующем разделе.
Get a bit of backbone boy!Всё, что мы узнали уже об остнастке, может быть применено также к creepycrawlies.py. Если мы хотим расширить функциональность сгенерированной модели, мы можем соединить модификатор арматуры со сгенерированным мешем. Мы также создадим объект арматуры с подходящим набором костей.
Наша задача уже облегчена, потому что мы уже сгруппировали вершины частей тела в модуле mymesh, так что связывание их с группой вершин и соответствующей костью тривиально. Не таким тривиальным будет создание самих костей, так как их может быть много, и их нужно разместить и соединить правильным способом.
Давайте посмотрим на то, как могли бы быть осуществлены некоторые существенные элементы (полный код смотрите в creepycrawlies.py). Сначала мы должны создать арматуру и сделать её редактируемой для добавления костей:
ar = Blender.Armature.New('BugBones')
ar.autoIK = True
obbones = scn.objects.new(ar)
ar.makeEditable()
Мы можем также задать любые атрибуты, которые изменяют поведение арматуры или способ её отображения. Здесь мы просто включаем свойство autoIK, так как это сделает манипуляции хвостом нашего создания, возможно очень длинным, намного проще для аниматора.
Следующий шаг - это создание костей для каждого набора вершин. Список vgroup в следующем коде содержит кортежи (vg,vlist,parent,connected), где vg - имя группы вершин а vlist - список индексов вершин, принадлежащих этой группе. Каждая кость, которую мы создаем, может иметь родителя и может физически быть соединена с родителем. Эти условия задаются частями кортежа parent (родитель) и connected (соединён):
for vg,vlist,parent,connected in vgroup:
bone = Blender.Armature.Editbone()
bb = bounding_box([verts[i] for i in vlist])
Для каждой кости, которую мы создаем, мы вычисляем габаритный ящик (bounding box) всех вершин в группе, на которые эта кость будет влиять. Дальше мы должны разместить кость. При способе, которым мы настраивали наше создание, все сегменты его тела вытягивались вдоль оси y, за исключением крыльев (wing) и ног (leg). Они вытягивались вдоль оси x. Мы сначала проверяем этот факт, и соответственно устанавливаем переменную axis (ось):
axis=1
if vg.startswith('wing') or vg.startswith('leg'):
axis = 0
Кости в составе арматуры индексируются по имени и позиции концов костей, сохраненных в их атрибутах head (голова) и tail (конец) соответственно. Так, если у нас есть родительская кость, и мы хотим определить её среднее значение координаты y, мы можем вычислить это следующим способом:
if parent != None :
parenty = (ar.bones[parent].head[1] +
ar.bones[parent].tail[1])/2.0
Мы вычисляем эту позицию, поскольку такие части как, например, ноги и крылья имеют родительские кости (то есть, они перемещаются вместе с родительской костью), но не подсоединены головой к хвосту. Мы разместим эти кости, начиная в центре родительской кости, и для этого нам нужна позиция родителя по y. Кости сегментов, лежащих вдоль оси y, сами позиционируются вдоль оси y, и, таким образом, имеют нулевые координаты x и z. Координаты x и z ног и сегментов крыльев берутся из их габаритных ящиков. Если кость подсоединена (connected), мы просто устанавливаем позицию её головы в копию позиции хвоста родителя (выделено ниже).
Класс Блендера Vector предоставляет функцию copy(), но как ни странно, нет функции __copy__(), так что он не будет играть по правилам с функциями из модуля Питона copy.
if connected:
bone.head = ar.bones[parent].tail.copy()
else:
if axis==1:
bone.head=Blender.Mathutils.Vector(0,
bb[1][0],0)
else:
bone.head=Blender.Mathutils.Vector(bb[0][1],
parenty,bb[2][1])
Положение хвоста кости рассчитывается аналогичным образом:
if axis==1:
bone.tail=Blender.Mathutils.Vector(0,bb[1][1],0)
else:
bone.tail=Blender.Mathutils.Vector(bb[0][0],
parenty, bb[2][0])
Последние шаги в создании кости - это добавление её к арматуре и установка специфичных для костей опций и всех родительских связей.
ar.bones[vg] = bone
if parent != None :
bone.parent=ar.bones[parent]
else:
bone.clearParent()
if connected:
bone.options=Blender.Armature.CONNECTED
Заметьте, что в предыдущем коде важен порядок действий: атрибут parent может быть присвоен или очищен только у костей, которые добавлены к арматуре, а опция CONNECTED может быть установлена только у кости, имеющей родителя.
Кроме того, мы должны остерегаться здесь некоторой специфичности Блендера. Родитель может быть установлен у кости назначением в её атрибут parent. Если у него нет родителя, этот атрибут возвращает None. Тем не менее, мы не можем назначить None в этот атрибут, мы должны использовать функцию clearParent(), чтобы удалить родительские отношения.
Материалы
Материалы — это то, что дает объекту внешнее проявление. В Блендере, материалы чрезвычайно разносторонни, и из-за этого довольно сложны. Почти любым аспектом того, как ведёт себя луч света при отражении от объекта, можно управлять, и не только простыми параметрами, но также картами изображений и нодовыми сетями.
Вплоть до 16 материалов может быть связано с объектом и, в пределах объекта, индивидуальные его части могут ссылаться на один из этих 16 материалов. На объектах Text3d, каждый индивидуальный символ может ссылаться на различный материал, и для кривых это так же для каждой управляющей точки.
С точки зрения разработчика, назначение материала объектам - процесс из двух шагов. Сначала, мы должны определить новый материал, и затем мы должны назначить материал или материалы на объект. Первый шаг может быть опущен, если мы можем сослаться на уже существующие материалы.
Если у объекта, подобному мешу, уже определены грани, тогда мы все еще должны назначать материал для каждой грани. Вновь создаваемые грани будут иметь назначенным активный материал, если активный материал задан.
Небольшой кусок кода иллюстрирует, как мы можем назначать материалы на Меш-объект. Здесь мы назначаем материал с белым рассеянным цветом для всех граней с чётным номером, и с черным рассеянным цветом для всех граней с нечетным номером на Меш-объекте в переменной ob.
me=ob.getData(mesh=1)
mats=[ Blender.Material.New(), Blender.Material.New()]
mats[0].rgbCol=[1.0,1.0,1.0]
mats[1].rgbCol=[0.0,0.0,0.0]
ob.setMaterials(mats)
ob.colbits=3
- 33 лучшие программы для ноутбука. Популярный самоучитель - Владимир Пташинский - Программы
- Защита вашего компьютера - Сергей Яремчук - Программы
- Delphi. Трюки и эффекты - Валерий Борисок - Программы
- Google Таблицы. Это просто. Функции и приемы - Евгений Намоконов - Программы
- 200 лучших программ для Linux - Сергей Яремчук - Программы