Как написать Plug-in для 3D Studio Max

Сразу хочу сказать, что писал я его для пятого <макса>, так что в ранних версиях может и не работать.

Лирическое отступление.

Плагин позволяет реализовать эффект остановки времени (как в <Матрице>, когда Тринити зависает в воздухе перед охранником). Это первый плагин, который я написал, в нем сразу же обнаружилась пара глюков, которые я постарался исправить.

Принцип работы.

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

Поехали.

Заходим во вкладку Utilites(Утилиты) командной панели (рис. 1), тыкаем по кнопке MAXScript, внизу развертывается панелька MAXScript, в которой есть 4 кнопочки. Если нажать Open Listener, откроется редактор скриптов. Здесь вы можете тестировать какие-либо команды. При нажатии на кнопку New Script открывается такое же окошко, что и до этого, но здесь уже можно писать целые скрипты, или даже плагины. Кстати, профессионалы пишут свои плагины не в MAX Script, а в других языках, это советуют даже сами разработчики <макса>, т.к. MAX Script довольно медленно работает, а это неприемлемо для визуализации. Но мы ведь только учимся: Наш плагин я решил запихать в Render Effects, хотя никакого отношения к эффектам визуализации у него, собственно, нет.

Итак, мы открыли окно нового скрипта. Давайте создадим диалог. Это здорово помогает при разработке нового плагина. Создайте новый Rollout (не знаю, как перевести), меню EditaNew Rollout. Открылось окно Visual Max Script. Слева наш роллаут, сюда мы будем ставить кнопочки, надписи и пр., справа свойства и методы выделенного объекта, внизу - панель инструментов. Поставьте в свойстве Width 320, это ширина диалога Rendering Effects, в свойстве Name - rolMain, это имя нашего роллаута (можете вставить какое хотите, но обязательно латинскими буквами), в свойстве Caption - название, например, Main Parameters. Лучше писать латиницей - впоследствии не возникнет проблем.

Вставьте в роллаут кнопку PickButton , которую назовите btnPick, а в свойстве Caption поставьте - Pick path. Добавьте Spinner , который назовите spnFrames, в свойстве Caption поставьте Frames, в свойстве Range поставьте [0,1000,10], Type - Integer. Добавьте еще один Spinner , который назовите spnFrame, Caption - Moment, Range - [0,1000,0].

Добавьте еще 3 спиннера, которые назовите spnXPos, spnYPos, spnZPos, Range сделайте [-1000,1000,0], это будут координаты центра, вокруг которого вращается камера.

Добавьте Edit Box , назовите его edtName, Caption - File Name.

Добавьте обычную кнопку Button , назовите ее btnSave, поставьте Caption - Choose.

И, наконец, добавьте еще одну кнопку Button , которую назовите btnRun, в Caption напишите Render, в Enabled - False

Закройте окно Visual Script, на вопрос о сохранении изменений ответьте утвердительно. В окне редактора появился код. Можно было кодировать все и без использования Visual Max Script, но с ним намного легче. В самом конце вставьте строку createdialog rolMain. Если вы свой роллаут называли не rolMain, то введите свое название. Теперь запустите свой диалог FileaEvaluate All. Выскочило диалоговое окно, которое пока ничего не делает. Это мы исправим.

Выберите из меню EditaEdit Rollout.

Выделите кнопку Pick path, которая выбирает путь. Перейдите во вкладку Event handlers (справа). Там будет только одно событие - picked. Тыкните по нему, появится диалог Edit Event Handler. Там введите следующий код:

if SuperClassOf(obj)==Shape then

(

btnPick.Caption=obj.name

btnRun.enabled=true

)

else

(

messageBox "Picked object is not shape" title:"Motion Flow"

)

Как вы могли заметить, команды MAX Script'а очень похожи на команды С++. Кратко поясню, что здесь происходит: в первой строке проверяется суперкласс выбранного объекта, то есть класс-родитель. Если он - форма (это линии, круги, овалы, прямоугольники и пр.), то написать на кнопке имя объекта и включить кнопку Render, если нет - показать сообщение о неправильном выборе и ничего не делать.

Снизу слева есть выпадающий список Control, где можно выбрать элемент управления.

Выберите кнопку btnSave.

Введите следующий код:

FilName=GetSaveFileName caption:"Save Image" types:"JPEG format|*.jpg|Bitmap|*.bmp|Targa Format|*.tga|TIFF Format|*.tif|Other Formats|*.*"

if getFilenameType FilName == '' then filName=FilName+".tga"

edtName.text=FilName

Переменной FilName присваивается значение стандартного диалога сохранения. types - типы файла (например, JPG или BMP). Далее проверяем наличие расширения у выбранного файла, если отсутствует - назначить .tga. Затем загоняем имя файла в поле ввода File name.

Выберите кнопку btnRun.

Теперь самое интересное.

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

x=spnXPos.value

y=spnYPos.value

z=spnZPos.value

fr=spnFrames.value

f=spnFrame.value

FilName=edtName.text

FilExt=getFileNameType FilName

FileIm=GetFileNamePath FilName+GetFileNameFile FilName

camPath=btnPick.object

X, Y, Z - координаты центра вращения камеры. fr - количество кадров для визуализации, f - кадр, в котором движение останавливается. FilName - полное имя файла, FilExt - расширение файла, FileIm - путь и имя файла (без расширения). camPath - путь передвижения камеры.

Проверим наличие имени файла. Если его нет, зададим вопрос, стоит ли продолжать?

if FilName=="" and queryBox "The sequense is not save. \n Do you wish to continue?" title:"Motion Flow" == true or FilName!="" then

И, непосредственно начнем выполнение.

(

camFollow=TargetCamera target: (CamTarg=targetObject pos:[x,y,z])

camFollow.pos.controller=path follow:false

posCont=camFollow.pos.controller

posCont.path=camPath

В первой строчке создается направленная камера с центром в точке (x,y,z). Назначаем нашей камере контроллер Path Constraint. Назначаем для контроллера наш путь.

Начинаем цикл визуализации.

for i=0 to fr do

(

if not keyboard.EscPressed then

(

posCont.percent=100/fr*i

a=i as integer

if a<10 then num="000"+a as string

if (a>=10) and (a<100) then num="00"+a as string

if (a>=100) and (a<1000) then num="0"+a as string

if (a>=1000) then num=a as string

camFollow.Name="Motion Flow "+num+" of "+(fr as string)

render camera:camFollow OutputFile:(FileIm+num+FilExt) frame:f progressbar:true vbf:off

)--end if

)-- end for

В первой строчке мы проверяем, была ли нажата клавиша Esc, если не нажата, то продолжать выполнение. Во второй строчке мы описываем местоположение камеры в процентах относительно пути. Строчки 3-7 предназначены для последующего использования при визуализации и сохранении файлов. Вообще-то эти нолики не имеют никакого значения, я их вставил просто для красоты. Так же для красоты я вставил строчку 8. При ее выполнении в заголовке окна визуализации появляется надпись типа "Motion Flow 0009 of 35, frame 56 (1:1)".

И, наконец, визуализация - восьмая строчка.

Осталась самая малость - удалить нашу камеру, чтобы непосвященный не догадался, как этот плагин был сделан, и чтобы впоследствии она нам не мешала.

delete camFollow

)--end if

Уф, вот и все. Закройте окошко редактора событий, нажав кнопку OK справа внизу. Закройте окно Visual Max Script.

Все, можно тестировать.

Создайте 2 каких-нибудь объекта, например, куб и круг вокруг куба (круг вокруг, прикольно:). Запустите наш скрипт. Попробуйте выбрать куб, нажав кнопку Pick Path. А теперь - круг. Введите нужное вам количество кадров. Выберите, куда сохранять, запустите кнопкой Render. Попробуйте остановить выполнение, нажав Esc (жать придется неоднократно, т.к. проверка нажатия клавиши производится между визуализациями в очень небольшой промежуток времени и вероятность сразу попасть крайне мала L )

Все работает, но мы собирались делать плагин, а не скрипт. Нужно определиться, куда он подходит. Вообще-то он не подходит никуда, можно сделать его отдельной утилитой, но мы вставим его в Render Effects. Итак, в самом начале вставьте строчку:

plugin RenderEffect FlowMo name:"Motion flow" classID:#(0xd1a09a62, 0x9f4f8047)

(

classID можете сгенерировать и свой, для этого откройте MaxScript Listener и напишите там:

genclassid()

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

Да, чуть не забыл, поставьте еще одну закрывающую скобку в конце кода и удалите строку createdialog rolMain Теперь можно запускать. Запустите скрипт. Наш новоиспеченный плагин можно открыть из меню RenderaEffects.., щелкнув по кнопке Add и выбрав Motion Flow. Можете скопировать наш плагин в папку Plugins корневой папки 3DSMax, тогда он будет запускаться автоматически. На рисунке вы видите, как этот плагин выглядит у меня.

PS

Я написал этот плагин, чтобы сделать ролик, в котором происходит взрыв и время останавливается - получилось даже лучше, чем я ожидал. Существует только одна проблема - приходится потом собирать изображения в ролик. Лучше было бы сделать это в самом скрипте, но я, так и не смог придумать, как это сделать, к тому же их можно прекрасно собрать в Adobe Premiere, тем более это все равно нужно будет впоследствии вставлять в больший ролик.

PS PS

Если найдете какие-либо глюки - радируйте.

Карачковский Евгений.

E-KAR@Mail.Ru


434 0 850 5
3
2006-03-28
Молодец!!!!!!!!1
2006-06-12
Евгений, ты сам-то понял, что написал! Респект тебе.
2006-10-19
Блин, я думал об этом но не знал как выразить.У тебя получилось!
RENDER.RU