Рейтинговые книги
Читем онлайн Написание скриптов для Blender 2.49 - Michel Anders

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 6 7 8 9 10 11 12 13 14 ... 58

Как только мы извлекли наши списки координат вершин и индексов граней из модуля mymesh, нам нужен некоторый способ для создания нового меш-объекта в нашей сцене и добавления объектов MVert и MFace в этот меш. Это можно осуществить, например, так:

me=Blender.Mesh.New('Bug')

me.verts.extend(verts)

me.faces.extend(faces)

scn=Blender.Scene.GetCurrent()

ob=scn.objects.new(me,'Bug')

scn.objects.active=ob

me.remDoubles(0.001)

me.recalcNormals()

Первая строка создает новый меш-объект с именем Bug (Жук). Он не будет содержать никаких вершин, рёбер или граней, не будет вставлен в объект Блендера, и не будет подключен пока ни к какой Сцене. Если имя меша уже существует, к нему будет добавлен уникальный цифровой суффикс (например, Bug.001).

Следующие две строки действительно создают геометрию в меше. Атрибут verts – это место, куда ссылается наш список объектов MVert. У него есть метод extend(), который принимает список кортежей, каждый из которых содержит координаты x, y, и z создаваемых вершин. Точно так же метод extend() атрибута faces принимает список кортежей, каждый из которых содержит три или больше индексов, указывающих на вершины, которые вместе определяют грань. Порядок здесь важен: нам нужно сначала добавить новые вершины; в противном случае вновь созданные грани не смогут ссылаться на них. Нет необходимости определять какие-либо рёбра, так как добавление граней также неявно создаст рёбра, которые ещё не присутствуют.

Меш по своей сути еще не является объектом, которым может манипулировать пользователь, так что в следующих нескольких строках (выделено), мы извлекаем текущую сцену и добавляем в неё новый объект. Аргументы функции new() - меш-объект, который мы создали ранее, и имя, которое мы хотим дать объекту. Имя, даваемое объекту, может быть таким же, как и данное мешу, так как имена мешей и имена объектов существуют в различных пространствах имён. Как и с мешем, существующее имя будет сделано уникальным посредством добавления суффикса. Если имя опущено, новый объект получит в качестве имени по-умолчанию тип своего аргумента (Mesh в нашем случае).

Вновь созданный объект будет выбран, но не активен, так что мы исправим это, присвоив наш объект в scene.objects.active.

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

Преобразование топологии меша

Создание существа из строительных блоков требует, чтобы мы применяли дублирование, масштабирование, и отражение к этим строительным блокам прежде, чем мы склеим их вместе. В Блендере 2.49, это означает, что мы должны определить некоторые вспомогательные функции (утилиты), чтобы выполнить эти действия, так как они не присутствуют в API. Мы определяем эти вспомогательные функции в модуле Tools (инструменты), но мы осветим некоторые из них здесь, так как они покажут несколько интересных методов.

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

Схема кода сшивания рёберных циклов

В функции, которая создает новые грани, мы должны выполнить следующие шаги:

1. Удостовериться, что оба рёберных цикла цикла имеют одинаковую и ненулевую длину.

2. Для каждого ребра в цикле 1:

1. Найти ребро в цикле 2, которое ближе всего.

2. Создать грань, соединяющую эти два ребра.

Функция, которая осуществляет эту довольно сложную на вид схему:

def bridge_edgeloops(e1,e2,verts):

    e1 = e1[:]

    e2 = e2[:]

    faces=[]

    if len(e1) == len(e2) and len(e1) > 0 :

Функция принимает аргументы: два списка рёбер и список вершин. Рёбра представлены в виде кортежей двух целых (индексы в списке вершин verts), а вершины - в виде кортежей координат x, y, и z.

Первая вещь, которую мы сделаем - создадим копии двух рёберных списков, поскольку мы не хотим испортить списки в их оригинальном контексте. Список граней, который мы будем строить, инициализируется в пустой список, и мы проверяем разумность и равенство длин обоих рёберных списков. Если это подтверждается, мы приступаем к следующему куску:

for a in e1:

    distance = None  # расстояние

    best = None      # лучший

    enot = []        # отвергнутые рёбра

Мы повторяем по каждому ребру в первом списке, ссылаясь на это ребро через a. параметр distance содержит расстояние до ближайшего ребра во втором рёберном списке, а best будет ссылкой на это ребро. enot - список, который копит все рёбра из второго списка, которые находятся на большем расстоянии, чем наилучшее.

В конце каждой итерации, enot будет содержать все рёбра из второго списка минус одно - которое мы считаем ближайшим. Затем мы переназначаем enot на второй список, таким образом второй список уменьшается на одно ребро с каждой итерацией. Мы заканчиваем, как только второй список рёбер будет исчерпан:

while len(e2):

    b = e2.pop(0)

Текущее ребро из второго списка, которое мы рассматриваем, называется b. Для наших целей, мы определяем расстояние между a и b как сумму расстояний между соответствующими вершинами в a и b. Также мы проверяем, не окажется ли короче сумма расстояний до перевёрнутых вершин b. Если получилась такая ситуация, мы меняем вершины в ребре b. Это может казаться сложным способом действий, но суммированием двух расстояний мы гарантируем, что рёбра, которые сравнительно коллинеарны (параллельны) - привилегированы, тем самым уменьшая число неплоских граней, которые будут созданы. Проверяя, не приведёт ли перевёрнутый второй край к более короткому расстоянию, мы предотвращаем образование   искорёженного   в   виде   галстука-бабочки четырёхугольника, как проиллюстрировано на следующем рисунке:

Реализация будет выглядеть похоже на предшествующий рисунок, где выделенные вектора - псевдонимы на объект Mathutil.Vector, преобразующий наши кортежи с координатами x, y, и z в соответствующие векторы, которые мы можем вычитать, складывать, и получать их длину.

Сначала мы вычисляем расстояние:

    d1 = (vec(verts[a[0]]) - vec(verts[b[0]])).length +

    (vec(verts[a[1]]) – vec(verts[b[1]])).length

Затем мы проверяем с перевёрнутым ребром b, будет ли в результате расстояние короче:

    d2 = (vec(verts[a[0]]) - vec(verts[b[1]])).length +

    (vec(verts[a[1]]) - vec(verts[b[0]])).length

    if d2<d1 :

        b =(b[1],b[0])

        d1 = d2

Если рассчитанное расстояние не самое короткое, мы откладываем ребро для следующей итерации, если оно не первое, с которым мы столкнулись:

    if distance == None or d1<distance :

        if best != None:

            enot.append(best)

        best = b

        distance = d1

    else:

        enot.append(b)

Список отклонённых рёбер становится новым e2, затем мы заполняем список граней новой парой рёбер, и переходим к новой итерации по первому списку рёбер (a) – доп. пер.

e2 = enot

faces.append((a,best))

Наконец, мы преобразуем наш список граней, состоящий из кортежей двух рёбер, в список кортежей из четырех индексов:

return [(a[0],b[0],b[1],a[1]) for a,b in faces]

Есть много больше в этом скрипте, и мы вновь будем рассматривать creepycrawlies.py в следующей главе, где мы добавим модификаторы, группы вершин и арматуру к нашей модели. Иллюстрация показывает образцы бестиария, которые могут быть созданы скриптом.

Ослепите вашего босса - гистограммы в стиле Блендер

Чтобы доказать, что Блендер адаптируется ко многим задачам помимо интерактивного создания 3D-графики, мы покажем Вам, как импортировать внешние данные (электронная таблица в формате CSV) и автоматизировать задачу создания и рендеринга представленной в 3D гистограммы.

1 ... 6 7 8 9 10 11 12 13 14 ... 58
На этой странице вы можете бесплатно читать книгу Написание скриптов для Blender 2.49 - Michel Anders бесплатно.

Оставить комментарий