Создание существа из строительных блоков требует, чтобы мы применяли дублирование, масштабирование, и отражение к этим строительным блокам прежде, чем мы склеим их вместе. В Блендере 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 :
Функция принимает аргументы: два списка рёбер и список вершин. Рёбра представлены в виде кортежей двух целых (индексы в списке вершин
Первая вещь, которую мы сделаем - создадим копии двух рёберных списков, поскольку мы не хотим испортить списки в их оригинальном контексте. Список граней, который мы будем строить, инициализируется в пустой список, и мы проверяем разумность и равенство длин обоих рёберных списков. Если это подтверждается, мы приступаем к следующему куску:
for a in e1:
distance = None # расстояние
best = None # лучший
enot = [] # отвергнутые рёбра
Мы повторяем по каждому ребру в первом списке, ссылаясь на это ребро через a. параметр
В конце каждой итерации,
while len(e2):
b = e2.pop(0)
Текущее ребро из второго списка, которое мы рассматриваем, называется
Реализация будет выглядеть похоже на предшествующий рисунок, где выделенные вектора - псевдонимы на объект
Сначала мы вычисляем расстояние:
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
b =(b[1],b[0])
d1 = d2
Если рассчитанное расстояние не самое короткое, мы откладываем ребро для следующей итерации, если оно не первое, с которым мы столкнулись: