Написание скриптов для Blender 2.49 - Michel Anders
Шрифт:
Интервал:
Закладка:
Сложная работа выполняется на выделенных строках. Здесь мы проходим циклом над всеми вершинами, и затем, во внутреннем цикле, проверяем каждое связанное с текущей вершиной ребро, чтобы извлечь вершину на другом конце из предварительно рассчитанного словаря. Затем мы вычисляем dv как рёберный вектор и добавляем скалярное произведение этого рёберного вектора и нормализованной вершинной нормали в список dvdn.
weights.append((v1.index,sum(dvdn)/max(len(dvdn),1.0)))
Предшествующая строка может выглядеть странно, но она добавляет кортеж, состоящий из индекса вершины и средней кривизны, где среднее число получается вычислением суммы всех величин кривизны по каждому ребру из списка, и деления её на количество величин в списке. Поскольку список может быть пустым (это случается, когда меш содержит не связанные вершины), мы предохраняемся от ошибки деления на 0, деля её на длину списка или на единицу, в зависимости от того, что больше. Таким образом, мы сохраняем наш код более удобочитаемый, избегая оператора if.
Схема кода: curvature.py
С функцией localcurvature() в нашем расположении, сам скрипт вычисления кривизны становится совсем кратким (полный скрипт доступен как curvature.py):
if __name__ == "__main__":
try:
choice = Blender.Draw.PupMenu("Normalization%t|Only
positive|Full range")
if choice>0:
ob = Blender.Scene.GetCurrent().objects.active
me = ob.getData(mesh=True)
try:
me.removeVertGroup('Curvature')
except AttributeError:
pass
me.addVertGroup('Curvature')
for v,w in localcurvature(me,
positive=(choice==1)):
me.assignVertsToGroup('Curvature',[v],w,
Blender.Mesh.AssignModes.ADD)
Blender.Window.Redraw()
except Exception as e:
Blender.Draw.PupMenu('Error%t|'+str(e)[:80])
Выделенные строки показывают, что мы удаляем возможно существующую группу вершин Curvature из Меш-объекта внутри блока try, и отлавливаем исключение AttributeError, которое будет вызвано, если группа отсутствует. Затем, мы снова добавляем группу с тем же именем, так что она будет полностью пустая. Последняя выделенная строка показывает, как мы добавляем отдельно каждую вершину, поскольку любая вершина может иметь отличающийся от других вес.
Все действия окружены конструкцией try … except , которая поймает любые исключения, и они появятся во всплывающем информационном сообщении, если произойдёт что-то необычное. Наиболее вероятно, это будет в ситуациях, когда пользователь забудет выбрать Меш-объект.
Собираем всё это вместе: Огни святого Эльма
Иллюстрация испускания из заострённого стержня была сделана моделированием простого объекта стержня вручную, и, затем, вычислением кривизны с помощью curvature.py.
Затем, была добавлена система частиц и параметр плотности (density) в панели Extra был настроен на группу вершин Curvature. Стержню и системе частиц были даны отдельные материалы: простой серый и белое Хало соответственно. Частицы были симулированы для 250 кадров, и для иллюстрации представлен кадр 250.
Кости
Арматура может считаться основой анимации, поскольку деформирует меш управляемым способом, который можно задавать ключами в данных кадрах, необходима для аниматоров, чтобы придавать позы их персонажам удобно контролируемым способом.
Реализация арматуры Блендера обеспечивает риггера и аниматора подавляюще большим количеством возможностей, но в конце концов арматура в первую очередь набор связанных костей, где каждая кость деформирует часть меша. Перемещения этих костей друг относительно друга могут быть обусловлены несколькими различными ограничениями.
Хотя кости можно конфигурировать для работы так, чтобы они влияли через envelope (конверт), тем самым деформируя любую вершину целевого меша в пределах определенного радиуса, их можно также сконфигурировать, чтобы деформировать только те вершины, которые принадлежат группе вершин с именем, совпадающим с именем этой кости. Такая деформация в дальнейшем управляется весом вершины в группе вершин, давая нам возможность точной настройки влияния кости.
Тик-такЧтобы проиллюстрировать основные возможности арматуры, мы создадим риг простой модели часов. Часы - это единый меш, состоящий из трех отдельных, не соединённых между собой субмешей - body (тело), little hand (маленькая рука), и big hand (большая рука). (Здесь автор, типа, пошутил. В английском языке стрелки часов почему-то называются «hand», что одновременно означает «ладонь» или «рука». Ну в статье стрелки и выполнили в виде реальных рук. Я долго не мог решить, как же лучше перевести эти little hand и big hand. - прим. пер.) Вершины каждой руки часов принадлежат двум отдельным вершинным группам - одна половина часовой руки (Arm), подключена к центру часов, и для конца руки (или ладони, Hand) отдельно. Эта настройка позволяет создать мультяшную анимацию наподобие карикатуры, где мы, например, можем сделать след конца руки фактическим движением.
Схема кода: clock.py
Мы должны предпринять следующие шаги, чтобы оснастить наши часы предлагаемым способом:
1. Импортировать данные меша
2. Создать меш часов
3. Создать вершинные группы
4. Создать объект арматуры
5. Создать кости в составе арматуры.
6. Связать модификатор с арматурой
Перевод из схемы в код - почти один в один, только нужно повторить множество инструкций для каждой из костей (полный код доступен как clock.py):
me=Blender.Mesh.New('Clock')
me.verts.extend(clockmesh.Clock_verts)
me.faces.extend(clockmesh.Clock_faces)
scn=Blender.Scene.GetCurrent()
ob=scn.objects.new(me)
scn.objects.active=ob
me.addVertGroup('BigHand')
me.assignVertsToGroup('BigHand',
clockmesh.Clock_vertexgroup_BigHand,
1.0, Blender.Mesh.AssignModes.ADD)
… <аналогичный код для вершинных групп LittleHand,
BigArm и LittleArm опущен> …
ar = Blender.Armature.New('ClockBones')
ar.envelopes=False
ar.vertexGroups=False
obbones = scn.objects.new(ar)
mod = ob.modifiers.append(Blender.Modifier.Types.ARMATURE
mod[Blender.Modifier.Settings.OBJECT]=obbones
mod[Blender.Modifier.Settings.ENVELOPES]=False
mod[Blender.Modifier.Settings.VGROUPS]=True
ar.makeEditable()
bigarm = Blender.Armature.Editbone()
bigarm.head = vec(0.0,0.0 ,0.57)
bigarm.tail = vec(0.0,0.75,0.57)
ar.bones['BigArm'] = bigarm
bighand = Blender.Armature.Editbone()
bighand.head = bigarm.tail
bighand.tail = vec(0.0,1.50,0.57)
bighand.parent = bigarm
ar.bones['BigHand'] = bighand
… <аналогичный код для маленькой руки опущен> …
ar.update()
obbones.makeParent([ob])
Важные моменты выделены. Сначала, мы отключаем envelopes и свойства vertexGroups у объекта арматуры. Это может показаться странным, но эти свойства являются остатками от того времени, когда арматура не была модификатором, приложенным к мешу, а работала через родительское (parented) влияние на Меш-объект (по крайней мере, насколько Я могу судить, доступная документация немного невнятна в этом месте). Мы определяем, какое влияние использовать, устанавливая свойства в модификаторе арматуры.
После связывания арматурного модификатора с нашим Меш-объектом, мы создадим нашу арматуру кость за костью. Прежде, чем мы добавим какие-либо кости в арматуру, мы должны вызвать её метод makeEditable(). Заметьте, что этот режим редактирования для арматур отличен от режима редактирования для других объектов, которые можно задавать с помощью функции Blender.Window.editMode()! Как только мы закончим, мы возвращаемся в нормальный режим снова, вызывая метод update().
Вы можете обратить внимание, что при создании нашей арматуры мы создём экземпляры объектов Editbone. Вне режима редактирования эти те же кости ссылаются на объекты типа Bone. Оба ссылаются на одну и ту же кость, но предлагают различную функциональность и атрибуты, подходящие для режима редактирования или для режима объектов. Для того, чтобы снабдить нас тем же подходом, Блендер также предоставляет объекты PoseBone для манипуляции костями в режиме Позы.