Чтение онлайн

ЖАНРЫ

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

Anders Michel

Шрифт:

Путь в обход этого препятствия - аргумент

idprop
, который передаётся в
doConstraint
. Перед тем, как вызвать
doConstraint
, Блендер сначала вызывает
doTarget
для каждого целевого объекта. Эта функция передаётся в виде ссылки на целевой объект и в свойства ограничения. Это позволяет нам включать ссылку на целевой объект в эти свойства, и поскольку эти свойства передаются в
doConstraint
, это обеспечивает нас средствами для передачи необходимой информации в
doConstraint
для получения Меш– данных. Есть мелочь, которую мы всё-же рассмотрим здесь: свойствами в Блендере могут быть только числа или строки, так что мы не можем на самом деле хранить ссылку на объект, но должны удовольствоваться его именем. Поскольку имя является уникальным, и функция Блендера
Object.Get
предоставляет способ извлекать объект по имени, это - не проблема.

Код для функций

doConstraint
и
doTarget
будет выглядеть так (полный код находится в
zoning_constraint.py
):

def doConstraint(obmatrix, targetmatrices, idprop):

obloc = obmatrix.translationPart.resize3D

obrot = obmatrix.toEuler

obsca = obmatrix.scalePart

# Получаем целевой меш

to = Blender.Object.Get(idprop['target_object'])

me = to.getData(mesh=1)

# получаем местоположение целевого объекта

tloc = targetmatrices[0].translationPart.resize3D

# ищем ближайшую вершину на целевом объекте

smallest = 1000000.0

delta_ob=tloc-obloc

for v in me.verts:

d = (v.co+delta_ob).length

if d < smallest:

smallest=d

sv=v

obloc = sv.co + tloc

# восстанавливаем матрицу объекта

mtxrot = obrot.toMatrix.resize4x4

mtxloc = Mathutils.TranslationMatrix(obloc)

mtxsca = Mathutils.Matrix([obsca[0],0,0,0],

[0,obsca[1],0,0],

[0,0,obsca[2],0],

[0,0,0,1])

outputmatrix = mtxsca * mtxrot * mtxloc

return outputmatrix

def doTarget(target_object, subtarget_bone, target_matrix,

id_prop_of_constr):

id_props_of_constr['target_object']=target_object.name

return target_matrix

Выделенные строки показывают, как мы передаем имя целевого объекта в doConstraint. В doConstraint мы сначала извлекаем целевой меш. Это может вызвать исключение, например, если целевой объект не является мешем, но оно будет поймано Блендером самостоятельно. Тогда ограничение не станет воздействовать, ошибка будет показана в консоли, но Блендер продолжит нормальную работу.

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

Выравнивание вдоль вершинной нормали

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

Следовательно, после обнаружения ближайшей вершины, мы определяем угол между вершинной нормалью и осью z (то есть, мы произвольно определяем направление Z как 'вверх'), затем вращаем ограничиваемый объект на тот же самый угол вокруг оси, перпендикулярной как вершинной нормали, так и оси z. Это сориентирует ограничиваемый объект вдоль этой вершинной нормали. Если ограничиваемый объект был вручную повёрнут до добавления ограничения, эти предыдущие вращения будут потеряны. Если это - не то, что нам нужно, мы можем применить все вращения перед добавлением ограничения.

Для того, чтобы осуществить эту возможность выравнивания, наш код изменится (

zoning_constraint.py
уже содержит эти изменения):
doConstraint
должно вычислять поворотную часть матрицы преобразования. Мы должны вычислить угол вращения, ось вращения, и затем новую матрицу вращения. Выделенная часть следующего кода показывает, что основные инструменты для этих вычислений уже предусмотрены модулем
Mathutils
:

vnormal = sv.no

if idprop['NormalAlign'] :

zunit=Mathutils.Vector(0,0,1)

a=Mathutils.AngleBetweenVecs(vnormal,zunit)

rotaxis=zunit.cross(vnormal)

rotmatrix=Mathutils.RotationMatrix(a,4,"r",rotaxis)

mtxrot = rotmatrix

else:

mtxrot = obrot.toMatrix.resize4x4

В предыдущем коде мы можем видеть, что мы сделали выравнивание зависимым от свойства

NormalAlign
. Только если оно задано, мы вычисляем необходимое преобразование. Следовательно, нам нужно адаптировать также функцию
getSettings
, поскольку пользователю нужен способ выбирать, нужно ему выравнивание или нет:

def getSettings(idprop):

if not idprop.has_key('NormalAlign'):

idprop['NormalAlign'] = True

align = Draw.Create(idprop['NormalAlign'])

block = []

block.append("Additional restrictions: ")

block.append(("Alignment: ",align,

"Align along vertex normal"))

retval = Draw.PupBlock("Zoning Constraint", block)

Поделиться с друзьями: