KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программы » Michel Anders - Написание скриптов для Blender 2.49

Michel Anders - Написание скриптов для Blender 2.49

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Michel Anders, "Написание скриптов для Blender 2.49" бесплатно, без регистрации.
Перейти на страницу:

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



Две вещи могли бы помочь смягчить эту проблему. Одна - это добавить вес crease (складки) к рёбрам нашего выгравированного текста, этим самым взвешивая эти края сильнее, чем при расчете subsurface по умолчанию. Это может помочь, но может также отодвинуть нас от цели применения модификатора, так как это сделает эти края острыми. Следующий рисунок показывает результат: лучше, но все еще не выглядит идеально.



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



Конвертация объекта Text3d в меш

Объект  Text3d базируется на кривой с несколькими дополнительными параметрами. Блок данных, на который он ссылается - объект Кривой Блендера (Curve), и как только мы узнаем, как получить доступ к индивидуальным частям кривой, которые составляют каждый символ в нашем тексте, мы можем преобразовать эти кривые в вершины и рёбра. Все соответствующие функциональные возможности могут быть найдены в модулях Blender.Curve и Blender.Geometry.

В Блендере, отношение между объектом Text3d и объектом Curve (Кривой) более тонкое и запутанное, чем описано в основном тексте. Объект  Text3d - специализированная версия объекта Curve, подобно подклассу на объектно-ориентированном языке. Тем не менее, в API Блендера объект Text3d не является подклассом Curve, как и нет у него дополнительных атрибутов, доступных на том же экземпляре объекта. Звучит запутанно? Так и есть. Как же тогда Вы извлечете все атрибуты? Весь фокус в том, что вы можете использовать имя объекта Text3d, чтобы получить доступ к связанному с ним объекту Curve, как показывает этот маленький пример:

txt = ob.getData()

curve = Blender.Curve.Get(txt.getName())

Теперь мы можем использовать txt, чтобы иметь доступ к Text3d-специфичной информации (например, txt.setText('foo')) и curve, чтобы иметь доступ к Curve-специфичной   информации   (например, curve.getNumCurves()).


Объект Curve Блендера состоят из множества объектов CurNurb, которые представляют сегменты кривой. Единственный текстовый символ обычно состоит из одного или двух сегментов кривой. Маленькая буква e, например, состоит из внешнего сегмента и небольшого внутреннего сегмента кривой. Объекты CurNurb, в свою очередь, состоят из множества узлов или управляющих точек, которые задают сегмент кривой. В случае объектов Text3d эти узлы всегда являются объектами BezTriple, и модуль Geometry Блендера предоставляет нам функцию BezierInterp(), которая возвращает список координат, интерполированных между двумя точками. Эти точки и направляющие кривой в этих точках (часто называемые handle, рукоять), можно взять из объектов BezTriple. Результирующий код выглядит так (полный код является частью нашего пакета разработчика в Tools.py) (Эта и последующие функции этого раздела, несмотря на заверения автора, отсутствуют в файле Tools.py, прилагаемом ко 2-й главе, найти их можно только в файле engrave.py — прим. пер.):

import Blender

from Blender.Geometry import BezierInterp as interpolate

from Blender.Mathutils import Vector as vec

def curve2mesh(c):

   vlists=[]

   for cn in c:

      npoints = len(cn)


      points=[]

      first=True

      for segment in range(npoints-1):

         a=cn[segment].vec

         b=cn[segment+1].vec

         lastpoints = interpolate(vec(a[1]),vec(a[2]),

                         vec(b[0]), vec(b[1]),6)

         if first:

            first = False

            points.append(lastpoints[0])

            points.extend(lastpoints[1:])

      if cn.isCyclic():

         a=cn[-1].vec

         b=cn[0].vec

         lastpoints=interpolate(vec(a[1]), vec(a[2]),

                                vec(b[0]), vec(b[1]),6)

         points.extend(lastpoints[:-2])


      vlists.append(points)


   return vlists  

Выделенные строки показывают два важных аспекта. Первая показывает фактическую интерполяцию. Мы переименовали довольно неуклюжее имя функции BezierInterp() в interpolate(), и она принимает пять аргументов. Первые четыре берутся от двух объектов BezTriple, между которыми мы интерполируем. В каждом объекте BezTriple можно получить доступ к списку из трех векторов: входящая рукоять, позиция точки, и исходящая рукоять (смотри следующий рисунок). Мы передаем позицию первой точки и исходящей рукояти и позицию второй точки и входящей рукояти. Пятый аргумент является количеством точек, которые мы хотим получить на выходе функции interpolate().



Вторая выделенная строка заботится о замкнутых кривых - кривых, в которых их первые и последние точки связаны. Это является случаем всех кривых, которые формируют символы в тексте. Функция возвращает список списков. Каждый список содержит все интерполированные точки (кортежи из x, y, z координат) для каждой кривой. Заметьте, что некоторые символы состоят из более, чем одной кривой. Например, небольшая буква e во многих шрифтах, или буква o состоит из двух кривых, одна задаёт внешнюю границу буквы и одна внутреннюю.  Объект Text3d, содержащий текст Foo, например, возвращает список из пяти списков - первый будет содержать вершины, определяющие большую букву F, а второй и третий будут содержать вершины для двух кривых, которые создают маленькую букву o, так же будет с четвертым и пятым.


Выдавливание рёберного цикла

Выдавливание (Extrusion) является процессом, где мы дублируем вершины (и, возможно,  соединяющие их рёбра) и перемещаем их в некотором направлении, после чего мы соединяем эти дубликаты вершин с их оригиналами новыми рёбрами, и заканчиваем операцию, создавая новую грань между старыми и новыми вершинами. Нам нужно это для того, чтобы утопить очертание нашего текста, чтобы создать бороздку с вертикальными стенками. Функция extrude_selected_edges() в Tools.py принимает меш и вектор как аргументы, и выдавит вершины на выбранных рёбрах в меше в направлении вектора, добавляя все необходимые новые рёбра и грани. Поскольку эта техника является расширением того, что мы уже видели раньше, код не показан здесь.


Расширение (Expanding) рёберного цикла

Если у нас есть список рёбер, формирующих замкнутую кривую (или более одного), определяющий символ, мы хотели бы окружить эти рёбра дополнительным рёберным циклом, чтобы создать лучшее "выполнение" любого модификатора subsurface, который конечный пользователь может связать с нашим мешем. Это был бы довольно сложный процесс, если мы должны были бы вычислять это в 3D, но, к счастью, наши преобразованные символы имеют все свои вершины на плоскости xy (дело в том, что все символы в новых экземплярах Text3d объекта лежат на плоскости xy)..



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

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*