Если оба объекта имеют сравнимую массу, гравитационное искажение должно быть сравнимого размера на обоих объектах. У нас может появиться искушение добавить ограничения TrackTo
и moon_constraint.py
к обоим объектам, чтобы видеть эффект воздействия их друг на друга, но, к несчастью, это не будет работать, поскольку это создаст циклическую зависимость, и Блендер запротестует.
Это похоже на режим "snap to vertex" (привязка к вершине), который доступен в Блендере из меню Object | Transform | Snap (информацию о привязках смотрите тут: http://wiki.blender.org/index.php/Doc:Manual/Modelling/Meshes/Snap_to_ Mesh), за исключением того, что эффект не постоянный (объект вернётся в свою изначальную позицию, как только ограничение будет удалено) и силу ограничения можно регулировать (даже анимировать), изменяя движок Influence (Влияние).
В ограничениях, которые мы до сих пор разрабатывали, нам нужна была только позиция целевого объекта для вычисления эффектов на ограничиваемом объекте. Эту позицию было легко применять в функции doConstraint()
, так как матрицы целей принимались в качестве аргументов. Теперь мы все же встречаем другой вызов: если мы хотим привязать к вершине, мы должны иметь доступ к данным меша целевого объекта, но целевой объект не передаётся в функцию doConstraint()
.
Путь в обход этого препятствия - аргумент 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() мы сначала извлекаем целевой меш. Это может вызвать исключение, например, если целевой объект не является мешем, но оно будет поймано Блендером самостоятельно. Тогда ограничение не станет воздействовать, ошибка будет показана в консоли, но Блендер продолжит нормальную работу.