Мы уже видели, что модуль Блендера Mathutils имеет функцию, вычисляющую угол, так что наш код является очень кратким, так как реальную работу делает единственная функция, показанная ниже. (Полный скрипт предоставлен как sharpfaces.py.)
def sharpfaces(me,minimum_angle):
for face in me.faces:
n = len(face.verts)
edges = [face.verts[(i+1)%n].co - face.verts[i].co
for i in range(n)]
for i in range(n):
a = AngleBetweenVecs(-edges[i],edges[(i+1)%n])
if a < minimum_angle :
face.sel = 1
break
Заметьте, что мы не делаем различий между треугольными гранями и четырёхугольными, так как и те и другие могут иметь края, соединённые острым углом. Выделенная часть в предыдущем коде показывает одну тонкую деталь: всякий раз, когда мы вычисляем угол между нашими двумя рёберными векторами, мы инвертируем один из них, потому что для вычисления правильного угла оба вектора должны порождаться в одной вершине, а мы вычислили их все, последовательно указывая от одной вершины на другую.
Различие проиллюстрировано на следующем рисунке:
Выбор вершин со множеством рёбер
В идеале меш должен содержать грани, которые состоят из только четырех вершин (эти грани обычно именуются quads — четырёхугольники), и у них должны быть относительно одинаковые размеры. Такая конфигурация оптимальна при деформации меша, что часто бывает необходимо в анимации. Конечно, нет ничего действительно ужасного в трехсторонних гранях (tris), но в общих чертах лучше избегать их, поскольку небольшие треугольные грани всё портят при применении модификатора subsurface, заставляя его показывать неприглядную рябь.
Но даже когда у вас есть меш, состоящий только из четырёхугольников, некоторые вершины являются центром более, чем четырех рёбер. Эти вершины иногда называют полюсами, отсюда и название скриптов в следующих разделах. Если количество рёбер чрезмерное, скажем шесть или больше (как показано в предыдущем скриншоте), такой участок может стать трудным для деформации, и трудным для манипуляций разработчиком модели. В большом и сложном меше эти вершины может быть сложно находить и, следовательно, нам нужно средство выбора таких вершин.
Для того чтобы выбрать вершины с определённого числа шагов, мы можем выполнить следующие шаги:
1. Независимо проверить, что активный объект - это меш.
2. Независимо убедиться, что мы - в режиме объектов.
3. Показать всплывающее меню для ввода минимального количества рёбер.
4. Для каждой вершины:
• Итерация по всем рёбрам, подсчет вхождений вершины
• Если счет - больше или равен минимуму, выбрать вершину
Этот метод - прямой и простой. Функция, которая ответственна за фактическую работу, показана ниже (полный скрипт называется poleselect1.py). Она близко следует нашей схеме. Фактический выбор вершин осуществляется путем присвоения атрибуту вершины sel. Заметим также, что атрибуты v1 и v2 объекта ребра не являются индексами в атрибуте verts нашего меша, а ссылаются на объекты MVert. Вот почему нам нужно извлекать атрибуты index для сравнения.
def poleselect1(me,n=5):
for v in me.verts:
n_edges=0
for e in me.edges:
if e.v1.index == v.index or
e.v2.index == v.index:
n_edges+=1
if n_edges >= n:
v.sel = 1
break
Вы вероятно обратили внимание, что мы повторяли обход списка рёбер по новой для каждой вершины (выделено в предыдущем коде). Это может быть дорого с точки зрения производительности и эта стоимость даже усложнена необходимостью сравнивать индексы, которые нужно извлекать снова и снова. Возможно ли написать более эффективный код, который, тем не менее, останется удобочитаемым? Да, если мы будем следовать этой стратегии: