Выражение для Y

furmanOFF

Идея написания данного урока пришла после проекта включающего в себя четырехтактный, двухцилиндровый мотор.

Главная задача состоит в том, чтобы заставить одну деталь (а именно «коленчатый вал») управлять всеми остальными, тогда анимируя только вал, мы анимируем весь мотор.

В процессе выполнения задачи, для управления положением и вращением объектов, будем пользоваться Expression Controller.

Expression Controller дает возможность описать параметры объекта математическими и некоторыми логическими формулами.

Рассмотрим окно Expression Controller.

В поле Create Variables обозначаются переменные (скалярные и векторные), в этом уроке будем пользоваться только скалярными.

Созданные переменные показаны в поле Scalars, им можно присвоить конкретное значение (Assign to Constant) или значение параметра

какого-нибудь объекта (Assign to Controller).

Поле Description содержит описания и комментарии.

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

Иными словами выражение должно стоять на месте где подразумевается параметр предмета (в случае задавания положения объекта [выражение для X , выражение для Y , выражение для Z]).

Для выражений важно написание каждой буквы, поэтому чаще сверяйтесь с написанием, посмотрев его в Function List.

Кнопки Save и Load сохраняют и загружают выражения с переменными.

Debug показывает нынешние значения переменных и выражений.

Evaluate применяет выражение к объекту.

Close закрывает окно.

Приступим к созданию двигателя.

Вот движущиеся детали нашего двигателя:

Коленчатый вал

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

Важно чтоб контроллер вращения вала был Euler XYZ. К тому же проще всего будет расположить вал на нулевых координатах.

Шатун

Длину этой детали необходимо знать (для этого можно воспользоваться измерителем дистанции или рулеткой).

Точнее расстояние от Pivot Point до места, где поршень крепится к шатуну, при анимации поршня это будет иметь значение.

Pivot point шатуна важно расположить в месте где он должен крепится к валу. Лучше всего чтобы место крепления шатуна находилось прямо над Pivot Point вала (при начальном его положении) тогда поворот вала будет описывать поворот оси шатуна.

Далее его можно привязать к валу, но я использовал Position Expression Controller.

Для этого в панели Motion выбираем контроллер позиции и жмем Assign Controller, где выбираем Position Expression.

В поле выражений вписываем такое:

[0,

StartX+r*cos(-radToDeg(a)+Starta),

StartY+r*sin(-radToDeg(a)+Starta)]

Данное выражение означает присвоить положение:

X=0

Y=StartX+r*cos(a+Starta)

Z=StartY+r*sin(a+Starta)

Что задает положение шатуна относительно вала.

Далее надо задать скалярные переменные a, r, StartX и StartY вписав каждое имя в Create Variables и нажав Create.

Где a – угол поворота коленчатого вала. Ей мы присвоим значение вращения вала, для этого выбираем переменную и, нажав на Assign to Controller,

выбираем Коленчатый вал -> Transform -> Rotation -> Y_Rotation (например).

Здесь важно заметить, что операции с углами в Expression Controller проходят в градусах,

а значения в Euler XYZ в радианах, поэтому при использовании переменной, которой присвоено значение

вращения вала, необходимо преобразовывать ее значение в градусное с помощью команды -radToDeg(a), МИНУС потому, что отсчет угла там идет с другой стороны.

r – расстояние от Pivot Point шатуна до оси вала.

StartX, StartY – положение вала, в плоскости перпендикулярной оси вращения (когда она смотрит на нас).

Starta – Угол, на который отклонено место крепления шатуна.

Также можно загрузить мое, уже готовое, выражение, нажав кнопку Load (Важно помнить, что при загрузке выражений, переменным не присвоено никаких значений, придется присвоить их самим): Шатун

Теперь назначаем вместо контроллера вращения Look-At Constraint, сделав это через панель Motion.

Как цель выбираем поршень.

Поршень

Pivot Point поршня необходимо расположить в центре, а именно в месте крепления шатуна к поршню, это необходимо чтобы шатун «смотрел» именно на это место,

в результате нижеприведенных действий поршень будет «насажен» на шатун.

Его движение будет описывать Position Expression Controller, для этого выполняем аналогичные, предыдущему разделу, действия.

Ниже приведено объяснение выражения движения поршня:

На рисунке зеленым выделен сам поршень, красная ось его движения имеет угол наклона s.

r – расстояние от Pivot Point шатуна до оси вала.

a угол поворота вала.

с – длина шатуна, о которой я говорил на начале предыдущего раздела.

Путем несложных вычислений находим положение поршня относительно угла поворота вала:

m=c*cos(arcsin((r*sin(a-s))/c))

n=r*cos(a-s)

x=cos(s)*(m+n)

y=sin(s)*(m+n)

x=cos(s)*(c*cos(arcsin((r*sin(a-s))/c))+ r*cos(a-s))

y=sin(s)*(c*cos(arcsin((r*sin(a-s))/c))+ r*cos(a-s))

Выражение, заносимое в контроллер будет выглядеть так:

[0,

StartX+cos(s)*(c*cos(asin((r*sin(-radToDeg(a)-s+Starta))/c))+r*cos(-radToDeg(a)-s+Starta)),

StartY+sin(s)*(c*cos(asin((r*sin(-radToDeg(a)-s+Starta))/c))+r*cos(-radToDeg(a)-s+Starta))]

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

Или пользуемся готовым сохранением: Поршень

Полученную систему можно использовать в любых объектах имеющих поршень.

Следующие детали необходимы лишь для четырехтактного двигателя.

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

Служит для синхронизации и управления клапанами впуска/выпуска

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

a/2+Starta

Где a угол поворота вала.

Startaначальный угол головки распределителя ( его придется подобрать так, чтобы клапан двигался «вовремя», например если анимация двигателя начинается с такта впуска топлива, то следует расположить головку вала, контролирующего впускной клапан, боком к клапану).

Для задания вращения этого вала, в панели Motion, выберем поле Assign Controller>Rotation>Y_Rotation (ось Y, например), нажмем Assign Controller, где выбираем Float Expression.

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

a/2+degToRad(Starta)

В градусы мы угол не превращаем, потому что ответ нужен тоже в радианах.

Но для легкости начальный угол вводится в градусах, поэтому и переводится в радианы.

Можно воспользоваться готовым файлом: Распределительный вал

Клапан

Анимация клапана является трудной задачей, я решил ее так.

Я представил головку распределительного вала как совокупность полукруга и сдвинутой вниз параболы:

На данном рисунке (слева сверху) представлен срез этой самой головки, верхняя часть-полукруг радиуса r, причем радиус равняется координате x0 параболы при пересечении с 0:

r=sqrt(y0)

Здесь и далее sqrt() – означает корень (так корень пишется и в Expression).

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

Pivot Point клапана следует разместить как раз в этой точке.

Нам известны s – угол наклона оси клапана

(на практике берите 180 минус настоящий угол, потому что картинка не совсем соответствует системе координат в максе)

a – угол поворота распределительного вала (его мы назначаем с помощью Assign to Controller).

y0 – смещение параболы вниз, не сильно большое, задайте его, так чтобы в максимальном своем смещении (как раз на кончике параболы) клапан чуть приоткрывался.

Еще нам потребуется вспомогательный угол:

b=90-s+90-a=180-s-a

Из найденного нами отрезка c мы с легкостью найдем положение точки прикосновения в координатах (относительно оси распределительного вала).

n=c*sin(s)

m=c*cos(s)

Итак полученную задачу я решил так:

c2=k2+d2

d=k2-y0

c2=k4-2*k2*y0+y02+k2

k=cos(b)*c

c2=c4*cos4(b)-2*c2*cos2(b)*y0+y02+c2*cos2(b)

0=sqrt((1+2*cos2(b)*y0- cos2(b)+sqrt((cos2(b)-1)*(cos2(b)-1-4*cos2(b)*y0)))/(2*cos4(b))) — c

Решив данное уравнение относительно c, получим ответ :

с=sqrt((1+2*(cos(b)^2)*y0-(cos(b)^2)-sqrt(((cos(b)^2)-1)*((cos(b)^2)-1-4*(cos(b)^2)*y0)))/(2*(cos(b)^4)))

Где b=180-s-a

Теперь нам известны и m и n:

n=c*sin(s)

m=c*cos(s)

Теперь добавляя StartX+ m, получим нужное положение клапана по оси X.

А, отнимая StartY- n (ведь клапан движется вниз), получим положение клапана по оси Y.

Но полученное выражение неверно опишет движение клапана, ведь необходимо учесть, что с другой стороны у нас полукруг.

Для решения этой проблемы воспользуемся оператором if(условие, выражение1, выражение2)

что означает следующие: оператор выполняет выражение1, если условие верно и выражение2, если условие неверно.

Поэтому мы запишем следующие if(d>0, StartX+ c*cos(s), StartX+cos(s)*r) для движения по оси X,

и if(d>0, StartY+ c*sin(s), StartX+sin(s)*r) для движения по оси Y.

Почему как условие я взял d>0 ?

Потому что d= sin(b)*c – проекция отрезка c на ось Y головки, из рисунка видно, что если это значение превышает 0 то точка прикосновения находится в районе круга, и будет задавятся выражением cos(s)*r для X, и sin(s)*r для Y.

Если ось клапана находится по другую сторону НЕОБХОДИМО поменять знак с > на .

Теперь мы можем вывести остаточное выражение, зависящие от данных нам переменных.

Нужно заметить, что b =180+radToDeg(a)-s (помним, что угол поворота распределительного вала мы получаем в радианах, и отрицательного значения).

ИТАК, вот готовое выражение, зависящие от переменных a, s, StartX, StartY, y0:

[0,

if(

sin(180+radToDeg(a)-s)* sqrt((1+2*(cos(180+radToDeg(a)-s)^2)*y0-(cos(180+radToDeg(a)-s)^2)-
sqrt(((cos(180+radToDeg(a)-s)^2)-1)*((cos(180+radToDeg(a)-s)^2)-1-4*(cos(180+radToDeg(a)-
s)^2)*y0)))/(2*(cos(180+radToDeg(a)-s)^4)))>0,

StartX+cos(s)* sqrt((1+2*(cos(180+radToDeg(a)-s)^2)*y0-(cos(180+radToDeg(a)-s)^2)-sqrt(((cos(180+radToDeg(a)-
s)^2)-1)*((cos(180+radToDeg(a)-s)^2)-1-4*(cos(180+radToDeg(a)-s)^2)*y0)))/(2*(cos(180+radToDeg(a)-
s)^4))),StartX+cos(s)*sqrt(y0)),

if(

sin(180+radToDeg(a)-s)* sqrt((1+2*(cos(180+radToDeg(a)-s)^2)*y0-(cos(180+radToDeg(a)-s)^2)-
sqrt(((cos(180+radToDeg(a)-s)^2)-1)*((cos(180+radToDeg(a)-s)^2)-1-4*(cos(180+radToDeg(a)-
s)^2)*y0)))/(2*(cos(180+radToDeg(a)-s)^4)))>0,

StartY-sin(s)* sqrt((1+2*(cos(180+radToDeg(a)-s)^2)*y0-(cos(180+radToDeg(a)-s)^2)-sqrt(((cos(180+radToDeg(a)-s)^2)-
1)*((cos(180+radToDeg(a)-s)^2)-1-4*(cos(180+radToDeg(a)-s)^2)*y0)))/(2*(cos(180+radToDeg(a)-s)^4))), StartY
-sin(s)*sqrt(y0))]

Как и раньше, вы можете воспользоваться готовым файлом: Клапан

Ремень

Оставшейся ремень, я нарисовал сплайнами, и задав ему Bump карту, анимировал ее U offset относительно поворота коленчатого вала.

Для этого, задав карту, заходим в Wire Parameters->Наша карта->Maps->Bump->Coordinates->U_Offset, соединяем ее, таким же образом, с поворотом коленчатого вала, выбираем вал как главный (стрелочка влево), и вписываем слева такое выражение:

-Y_Rotation/2

Минус или плюс зависит от расположения ремня в пространстве (точнее его UVW Mapping), кстати я выбрал сферический,

Делитель подбирал также — чтоб он гармонично двигался вместе с ремнем. Советую просто сделать ваш Bump видимым во вьюпорте и подбирать направление и скорость движения карты.

Последней деталью двигателя, которой нам придется заняться, является свеча зажигания, а точнее ИСКРА.

Искра свечи зажигания

Искру, я сделал просто:

Провел две линии, задал им анимированный Noise, применив его ко всем вертексам кроме конечных.

В Render Effects, я задал Glow, примененный к линиям (через )

Чтобы линия и свечение виднелись, отметим линию как Renderable, а для Thikness зададим специальное выражение, с помощью Wire Parameters.

Для этого идем в Wire Parametrs->Modified Object->Line (Object)->Thickness

И, как показано на рисунке, соединяем с вращением коленчатого вала.

Теперь вписываем такое выражение:

floor(abs(0.1+sin(radToDeg(Y_Rotation)/2-90)))/20

Y_Rotation – если вал вращается по оси Y.

Тут floor() – оператор, который выдает наибольшее целое, меньшее данного числа.

abs() – модуль

Данное выражение выдает 1/20 каждый полный первый поворот вала, в ином случае оно выдает 0/20, что делает линию невидимой.

Получается, что Thickness линии = 1/20 = 0,05, каждый первый поворот вала (на начало такта Рабочего хода)

0,1 добавлено для того чтобы слегка продлить результат 1/20 (floor выдает 1), добавив, например 0,2 вы продлите искру еще на чуть-чуть.

-90 выполнено чтоб искра «попадала» точно на начало такта «Рабочего хода» (Взрыв), эта величина зависит от угла наклона цилиндра и времени когда будет проводится взрыв, поэтому проще всего будет поставить систему в положение, когда должна проходить искра, и подобрать такую величину, при которой искра виднеется (Thickness = 1/20).

Итог

Мы установили зависимость всех деталей от одной – коленчатого вала, теперь для анимации мотора (даже довольно сложного, не просто монотонного, хода) нужно только задать валу соответственное вращение и подправить его в

Curve Editor.

Итак мы научились пользоваться Expression Controller, если у вас что-то не вышло, посмотрите готовый мотор:

Motor.max

Большое спасибо и до свидания.

Понравилась статья? Поделиться с друзьями: