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

ЖАНРЫ

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

Anders Michel

Шрифт:

1-on-1 mappings

Вы можете задаться вопросом, почему мы должны были сначала вставить кривую 1:1. Отношение между ведомым каналом и его управляющим объектом содержит еще один слой и это - кривая, транслирующая значение на выходе управляющего объекта (pydriver) в финальное значение. Эту кривую можно изменять вручную, но обычно мы делаем всю точною настройку в нашем pydriver и просто вставляем кривую 1-к-1. Такой вариант работы настолько распространен, что Блендер обеспечивает специальный интерфейс для этой ситуации, так как весьма утомительно создавать необходимые кривые снова и снова для каждого управляемого канала.

Конечно, мы, возможно, достигли бы того же самого результата, ведя вращение напрямую через канал вращения объекта

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

Часовая стрелка из примера, - вот где использование pydriver действительно является правильным решением. (Хотя, изменяя непосредственно IPO-кривую, мы могли бы изменить темп изменения управляющего канала, но это было бы не столь же ясно, как простое выражение, и почти невозможно для более сложных отношений между объектами). Мы повторяем список действий, показанных ранее, но теперь для маленькой (часовой) стрелки и введем следующее pydriver– выражение:

ob('Knob').RotZ*(360/(2*m.pi))/10/12

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

knob
(кнопку) по ее оси Z, минутная стрелка будет следовать как и раньше, а часовая соответственно в 12 раз медленнее. Вместо того, чтобы вручную вращать кнопку, также возможно анимировать вращение кнопки, для анимации обеих стрелок часов. Полный результат доступен как
clock-pydriver.blend
, изображение часов с кнопкой, показано на следующем скриншоте:

Сокращения

В пределах pydriver– выражений можно использовать некоторые полезные сокращения, чтобы экономить на печатании. В пошаговом примере мы уже использовали сокращение

ob('<name>')
— это обращение к объектам Блендера по имени, аналогично, возможно получить доступ к Меш-объектам и материалам посредством
me('<name>')
и
ma('<name>')
соответственно. Кроме того, модуль
blender
доступен как
b
, модуль
Blender.Noise
как
n
, и модуль Питона
math
как
m
. Он позволяет выражениям использовать тригонометрические функции, такие как синус, например. Этих возможностей достаточно, чтобы покрыть много проблем, но их все равно не хватит если мы захотим, например, импортировать внешние модули. Есть путь избежать этих трудностей, мы его увидим в следующем абзаце.

Преодоление ограничений: pydrivers.py

Поле ввода для pydrivers ограничено 125 символами, и даже при том, что сокращения позволяют получить доступ к модулю Питона

math
и к некоторым из модулей Блендера, с помощью сокращённых выражений, предоставленного места достаточно мало. Кроме того, поскольку pydrivers должны быть выражениями Питона, весьма трудно отлаживать их (например, потому что Вы не можете вставить функцию print) или добавить нечто похожее на функциональность
if/then
. Последний пример до некоторой степени может быть преодолен хитрыми уловками, основанными на том факте, что Истина (
True
) и Ложь (
False
) в Питоне преобразуются в, соответственно, 1 и 0 внутри числового выражения, таким образом утверждение:

if a>b:

c=14

else:

c=109

эквивалентно:

c = (a>b)*14 + (a<=b)*109

Однако чувствуется неуклюжесть выражения, ведь мы оцениваем условие дважды. К счастью, и проблему пространства и ограничение единственного выражения можно преодолеть при использовании текстового блока с именем

pydrivers.py
. Если такой текстовый блок присутствует, его содержание доступно в виде модуля с именем p. Так, например, если мы определяем функцию
clamp
(зажим) в
pydrivers.py
таким образом:

def clamp(a,low,high):

if a<low : a=low

if a>high: a=high

return a

Мы можем вызвать эту функцию в нашем pydriver-выражении как

p.clamp (a, 14,109).

Мы будем использовать

pydrivers.py
в следующих примерах, не только потому, что это позволит применять более сложные выражения, но также и потому что ширина pydriver области еще меньше чем ее длина, что делает такое выражение очень трудным к прочтению, поскольку Вы должны постоянно пользоваться прокруткой для доступа ко всем частям выражения.

Внутреннее сгорание — корреляция сложных изменений

Предположим, что мы хотим продемонстрировать, как работает четырехтактный двигатель внутреннего сгорания. У такого двигателя есть множество движущихся частей, и многие из них связаны сложным образом.

Чтобы увидеть отношения между частями двигателя, будет полезно взглянуть на следующую иллюстрацию. На скриншоте перечислены названия, которые мы будем использовать, когда обратимся к различным частям мотора. (Я не автомобильный инженер и не механик, таким образом названия, возможно, не точны, но по крайней мере мы будем говорить об одних вещах. За дополнительной информацией Вы можете обратиться сюда

camshaft – распределительный вал

outlet valve – выпускной клапан

inlet valve – впускной клапан

cylinder – цилиндр

piston – поршень

connecting rod – шатун

drive shaft – ведущий или коленчатый вал

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

Ведущий вал просто будет следовать за вращением махового колеса, как более медленный механизм (это можно осуществить с помощью ограничения copy rotation объекта, но здесь мы всё хотим осуществить через pydrivers). Соответствующий pydrivers для канала

RotX
будет похож на это:

ob('Flywheel').RotX/(2*m.pi)*36

Это может выглядеть неуклюжим, но необходимо помнить - вращения сохраняются в радианах, в то время как pydriver– выражения должны возвращать вращение в градусах, поделенных на 10.

Высшая передача и оба распределительных вала будут также следовать за вращением махового колеса, но со скоростью, уменьшенной в два раза и с противоположным направлением вращения:

m.degrees(ob('Flywheel').RotX*-0.5)/10.0

Чтобы проиллюстрировать, как получить доступ к функциям в математическом модуле Питона

math
, мы не стали преобразовывать в градусы самостоятельно, а воспользовались функцией
degrees
, поставляемой с модулем
math
.

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