Выбрать главу

Самый легкий путь понять, что эти функции делают — посмотреть встроенный шаблон ограничения, который мы можем использовать в качестве основы, чтобы написать наши собственные ограничения. Он доступен в текстовом редакторе по меню Text | Script Templates | Script Constraint. При выборе этого меню будет создан новый текстовый блок, который можно выбрать в выпадающем списке внизу окна текстового редактора.

Шаблон ограничения в Блендере

Шаблон  ограничения содержит также много полезных комментариев, но здесь мы перечислим, по большей части голые функции. Кроме того, шаблон создает окно с фиктивными свойствами. Мы столкнемся со свойствами в следующей части, так что наш пример функции getSettings() здесь будет почти пуст. Как показано, функции будут осуществлять  функциональное ограничение, однако, ничего фактически не будет ограничено. Расположение, вращение, и масштаб ограничиваемого объекта останутся без изменений.

def doConstraint(obmatrix, targetmatrices, idprop):

    # Выделить компоненты преобразования для быстрого

    # доступа.

    obloc = obmatrix.translationPart() # перемещение

    obrot = obmatrix.toEuler()         # вращение

    obsca = obmatrix.scalePart()       # масштабирование

    # код, который реально меняет положение, вращение и

    # масштабирование, расположен здесь  

    # Конвертация обратно в матрицы положения, вращения,

    # масштаба,

    mtxloc = Mathutils.TranslationMatrix(obloc)

    mtxrot = obrot.toMatrix().resize4x4()

    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

В функцию  doConstraint() передаётся матрица преобразований ограничиваемого объекта и список матриц преобразования для каждого целевого объекта. Она также получает словарь свойств ограничения, к которым можно получить доступ по имени.

Первая вещь, которую мы делаем, - выделяем отдельные компоненты матрицы преобразования — перемещение, вращение, и масштаб ограничиваемого объекта. Частью перемещения будет вектор положения x, y, z, частью масштаба будет вектор масштабирующих коэффициентов вдоль осей x, y, z. Часть вращения будет представлена вектором Эйлера с вращением вокруг трех основных осей. (углы Эйлера очень упрощают работу с вращениями в трехмерном пространстве, но по началу являются довольно трудными для понимания. В википедии есть материал на эту тему http://ru.wikipedia.org/wiki/Углы_Эйлера, но пока что легче думать о углах Эйлера как о вращении вокруг осей x, y, z. Углы Эйлера трудны? Вот от кватернионов реально мозг взрывается! - возмущение пер.) Мы можем разделить любую матрицу преобразования целевого объекта так, как нам нужно, и затем изменить компоненты матрицы преобразования ограничиваемого объекта по своему усмотрению.

Функция, показанная здесь, не делает ничего, но преобразует различные компоненты преобразования обратно в матрицы, используя методы API (где это доступно), и затем рекомбинирует их, используя матричное умножение в единственную матрицу, которая впоследствии возвращается.

Функция doTarget() вызывается до вызова doConstraint() и даёт нам возможность манипулировать целевой матрицей прежде, чем она будет передана в doConstraint(). Аргументы - целевой объект, под-цель (или Кость или группа вершин для целевой арматуры или меша соответственно), целевая матрица, и свойства ограничения. В следующем разделе мы используем эту возможность для сохранения ссылки на целевой объект в свойствах, чтобы doConstraint() могла иметь доступ к этой информации. Если мы не хотим ничего изменять, то достаточно возвратить целевую матрицу, как показано в следующем коде:

def doTarget(target_object, subtarget_bone, target_matrix,

             id_properties_of_constraint):

    return target_matrix

Точно также, если нет необходимости предлагать пользователю возможность   определять   дополнительные   свойства, getSettings(), может иметь просто оператор return (возврат). Если мы хотим показать всплывающее меню, getSettings() - то место, где это нужно сделать. Мы также увидим такой пример в следующем разделе. Следующий код будет корректной реализацией "ничегонеделания":