Render.ru

Ускоряя Maya, послесловие. Скрипты для ускорения работы в Maya.

Лекс Дарлог (DRL)

Активный участник
Рейтинг
14
Но вот беда - скрипт эдитор и на ваш вариант, и на мой отвечает кучей абракадабры какой-то...(см. картинку)
Я сейчас ещё раз подумал... Прямые слэши в путях - это то, что нравится Майе. Но в данном случае команду обрабатывает не Майя, а винда. А она, в свою очередь, воспринимает прямые слэши не как символы в пути, а как спецсимволы для указания аргументов. Попробуй заменить в команде все прямые слэши на двойной бэкслэш (\\).

И насчёт "двух вариантов". На самом деле, это тот же самый вариант. Команде system в качестве аргумента надо передать строку, содержащую команду для операционки. Совершенно без разницы, взята эта строка из какой-то переменной, собрана по частям в скобках или введена напрямую в кавычках. 2-ой вариант отправляет то же самое значение, просто один из путей записан в отдельную переменную. Которая в данном случае не нужна. Твой вариант можно было написать и по-другому: если сперва собрать в одну переменную весь передаваемый код, а потом - просто выполнить:
Код:
system $переменная;
P.S.: чего-то меня на ночь глядя развезло: 3 поста подряд!
 
да вы вообще молодцы =)
не успеваю дописать драфт ответа, а уже новые сообщения появляются, которые делают этот драфт бессмысленным.
отпишитесь по итогу, разобрались или нет. у меня сейчас есть возможность погонять майя в русском винде.
 

Александр Иванов 97779

Активный участник
Рейтинг
5
Попробуй заменить в команде все прямые слэши на двойной бэкслэш (\\)
DRL получаю всё теже ругательства...Декодер выдаёт вот это:
"­е является в­утре­­ей или в­еш­ей
ком ­дой, испол­яемой прогр ммой или п кет­ым ф йлом."


На всякий случай полный "пост" из скрипт эдитора =):

cmdScrollFieldExecuter -e -execute scriptEditorPanel1Window|TearOffPane|scriptEditorPanel1|formLayout37|formLayout39|paneLayout1|formLayout40|tabLayout2|formLayout44|cmdScrollFieldExecuter4;
system "\"C:\\Program Files\\Adobe\\Adobe Photoshop CS6 (64 Bit)\\Photoshop.exe\" \"C:\\Users\\a_ivanow\\Desktop\\outUV.psd\"";
// Result: "C:\Program" ­Ґ пў«пҐвбп ў­гв७­Ґ© Ё«Ё ў­Ґи­Ґ©
Є®¬ ­¤®©, ЁбЇ®«­пҐ¬®© Їа®Ја ¬¬®© Ё«Ё Ї ЄҐв­л¬ д ©«®¬.
//
// Result: scriptEditorPanel1Window|TearOffPane|scriptEditorPanel1|formLayout37|formLayout39|paneLayout1|formLayout40|tabLayout2|formLayout44|cmdScrollFieldExecuter4 //
 
винда так ругается в том случае, если не находит указанную программу. Ниже пример сообщения из командной строки:

Код:
Microsoft Windows [Version 6.1.7601]
(c) Корпорация Майкрософт (Microsoft Corp.), 2009. Все права защищены.

C:\Users\d.astapkovich>хрень
"хрень" не является внутренней или внешней
командой, исполняемой программой или пакетным файлом.

C:\Users\d.astapkovich>
 

Александр Иванов 97779

Активный участник
Рейтинг
5
винда так ругается в том случае, если не находит указанную программу. Ниже пример сообщения из командной строки:
Спасибо Дима за ответ! Странно, но такая ругань возникает у меня на любую программу, пробовал ещё Bridge, FastStone Viewer, и в любом случае мат-перемат...=(
 
потыкался в проблему:
1. получается стабильно переключаться в фотошоп через
Код:
system "\"c:\\Program Files\\Adobe\\Adobe Photoshop CS5 (64 Bit)\\Photoshop.exe\""
именно переключаться, потому как если фотошоп не запущен, он нормально начинает загружаться и в 4-х из 5-ти случаев зависает на довольно продолжительное время на Initialazing panels, потом в итоге грузится. Maya при этом переодически перестает реагировать на любые действия, отвисает только при закрытии фотошопа. При запуске через cmd все работает нормально, о причинах такого поведеняи даже думать не хочу.

2. попытки запихнуть путь до картинки как дополнительный аргумент кончаются приведеленными в постах выше ошибками. Это очень странно, так как такая же строка без проблем отрабывает как надо в cmd. Попробовал разные варианты, ничего не работает. Аналогичное замечание про причиные поведения - мне до сих пор неводома глубина кривизны мозгов создателей Майя.

Но не было еще такой баги в графическом софте, с которой бы русский технический художник не справился бы или, по крайней мере, не научился бы жить. Сформулируем задачу и решение:
Суть задачи: передать через командную строку путь до программы и путь до файла.
Ограничение: нормально передается только один параметр.
Решение:
- делаем ярлык (lnk-файл), в котором зашиты оба параметра. Для этого создаем/копируем ярлык для фотошопа, открываем его свойства и добавляем в строку "Объект" путь до картинки, например:
Код:
"C:\Program Files\Adobe\Adobe Photoshop CS5 (64 Bit)\Photoshop.exe" "c:\Users\d.astapkovich\Temp\SpeedControl02.png"
- запускаем ярлык через команду system, например:
Код:
system "\"c:\\test.lnk\""
Поскольку это ярлык, можно положить его куда угодно, в т.ч. в майские настройки, чтобы не мучаться с абсолютными путями. Переде запуском лучше бы иметь уже запущенный фотошоп (см выше). Так же очевидно, что в этом раскладе uv-snapshot всегда должен ложиться в одно и то же место, перетирая предыдущий.

Из вышесказанного становится понятно, что любые дальнейшие улучшения лучше делать на стороне системы, т.е. писать хитрый батник (bat-файл) с преферансом и девицами.
 

Александр Иванов 97779

Активный участник
Рейтинг
5
Но не было еще такой баги в графическом софте, с которой бы русский технический художник не справился бы или, по крайней мере, не научился бы жить.
Спасибо преогромное!!!!!!! Теперь всё работает!!!! =))

Но вот странно, когда пытаюсь запустить ярлык через
system "\"c:\\test.lnk\""

Идёт вся та же ругань, а если использую
system ("load с:/test.lnk")

то работает всё на ура без тормозов и зависаний ни со стороны майки, ни со стороны фотошопа включен он или нет. =)

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

uvSnapshot -aa -n "C:/Users/a_ivanow/Desktop/outUV.png" -xr 2048 -yr 2048 -r 255 -g 255 -b 255 -o -ff png;

Дело в том что хочу облечь это дело в интерфейс со слайдером, который бы позволял менять разрешение снапшота. Причём желательно чтобы возможные разрешения выставлялись жёстко (128х128 256х256 512х512 и т.д.), но не представляю как зацепить нужные флаги команды...
Пока написал окошко с кнопочками, но выглядит весьма громоздко.
 

Вложения

Лекс Дарлог (DRL)

Активный участник
Рейтинг
14
Не совсем понял суть вопроса. В чём конкретно с этой командой не удаётся разобраться?
Хочется сделать слайдер, который бы прилипал к определённым позициям, или не получается запустить саму команду?
 

Александр Иванов 97779

Активный участник
Рейтинг
5
Хочется сделать слайдер, который бы прилипал к определённым позициям
Да, именно это хочется сделать, и плюс хочется понять как этому слайдеру сказать чтобы он менял разрешение снапшота (то есть изменял значения флагов -xr -yr команды uvSnapshot).
 
Александр, давай по частям:

1. исключительно имхо: жестко забивать в коде скрипта размеры текстур - это неверно. Все прогрессивное человечество при выборе размера создаваемой картинки обычно имеет следующий функционал:
- пресеты, которые выпадают в отдельном списке
- возможность ввести оба значения самостоятельно в 2 поля
- иногда еще бывают отдельные фишки типа фиксации пропорций: при изменении одного значения, второе автоматически изменяется через умножение на коэффициент "было/стало" первого значения

2. параметры из интерфейса передаются в команды через переменые. По-простому схему работы скрипта после нажатия на кнопку "Make snapshot" можно описать так:
- взять все нужные параметры из интерфейса и записать их в переменные. Для этого надо научиться использовать флаг "-q" в командах для работы с UI, например:
Код:
string $window;
columnLayout -adjustableColumn true;
    $myCheckBox = `checkBox -value 1 -label "White background"`;
showWindow $window;

$value = `checkBox -q -value $myCheckBox`;
print $value;
Код может быть нерабочим, так как пишу с компа, на котором нет Майя. Но для иллюстрации идеи подойдет: при создании элемента checkBox его имя записывается в переменную $myCheckBox. Ниже по коду эта переменная используется для того, чтобы запросить у checkBox его текущее значение с помощью флага value.


- вызвать нужную команду(ы), подставив в них нужные переменные в качестве параметров. Например, подставить 1 или 0 из во флаги r, g, b команды uvSnapshot:
Код:
uvSnapshot -aa -n "C:/Users/a_ivanow/Desktop/outUV.png" -xr 2048 -yr 2048 -r $value -g $value -b $value -o -ff png;
Если я написал код правильно, то у данной галочки будет вполне себе осмысленное значение: она будет переключать подложку между черным и белым.

3. даже такие несложные интерфейсы лучше сначала порисовать руками или сделать несколько прототипов в программах типа Balsamiq Mockups: http://builds.balsamiq.com/b/mockups-web-demo/ Подобный подход позволяет делать по 10-15 итераций над интерфейсом вообще без написания кода, что позволяет сфокусироваться именно на качестве UI, а не на болезненом изменении уже написанного.
 

Александр Иванов 97779

Активный участник
Рейтинг
5
параметры из интерфейса передаются в команды через переменые. По-простому схему работы скрипта после нажатия на кнопку "Make snapshot" можно описать так:
- взять все нужные параметры из интерфейса и записать их в переменные. Для этого надо научиться использовать флаг "-q" в командах для работы с UI, например
Спасибо за отзывчивость! Буду пробовать!
 

Лекс Дарлог (DRL)

Активный участник
Рейтинг
14
Дим,
Хоть я и "выступаю на твой сцене", но теперь я чувствую себя не успевшим вовремя ответить. :)

Александр Иванов,
Дополняя Димин ответ...
Вообще-то, есть софт, в котором как раз разрешения текстур задаются исключительно жёстко. xNormal, к примеру. Но, вот, недавно у нас возникла необходимость снять текстуры в 3К... Не 2, и не 4, а именно 3. Выкрутились сохранением файлов настроек и последующей автозаменой в Notepad++. Всё равно запекаем всегда пакетно, через батник.
О чём это я? Ах да... Я хочу сказать, надо всё-таки упрощать интерфейс и не давать пользователю лишних рулек, если они действительно не нужны. Особенно в Майе, в которой всегда в 10 раз больше элементов гуя, чем реально нужно. Но всё-таки перебарщивать тоже не хорошо, всё нужное надо оставить.
Конкретно в вопросе текстур - я пока что НИКОГДА не встречал необходимости запекать текстуры, не кратные 1К (или не являющиеся степенью двойки). Так что для данного интерфейса лично я не стал бы давать пользователю ни численных полей для ввода конкретного разрешения, ни дропдаунов с пресетами. Вместо них - одно-единственное float-поле "Введите, в скольких К (раз по 1024) должно быть разрешение". Человеку может максимум понадобиться сделать 512, 256 и т.п. Ничто не мешает ему ввести .5, .25 и т.п.
Если так уж хочется оставить возможность выбирать совсем конкретные разрешения - я бы сделал вообще другой режим запекания. То есть сделал бы tabLayout и вынес бы поля для введения точных значений на отдельную вкладку. Опять же - чтобы не выводить лишние настройки, когда они не нужны.
Галка сохранения пропорций - да, сделал бы. Но именно сохранения пропорций (как в ФШ), а не простого копирования значения из др. поля (как в Майе). Правда, по-хорошему, при включении придётся вешать scriptJob на обновление зависимого поля (со скрипт-джобами я, лентяй, так и не разобрался - так что помочь не смогу).

лично я для своих гуёв делаю так (и, как я понял, это хорошая практика):
  • Всегда запоминаю путь создаваемого окна (как описал Дима) в какую-нибудь переменную. Но именно путь окна, а не отдельных элементов. Вот так, к примеру:
    Код:
    $window = `window
    	-title "My super-puper window" // Заголовок окна
    	-mb 1 // Добавить в него меню
    	-mxb 0 // Убрать кнопку максимизации
    	-rtf 1 // Заставляет окошко при запуске увеличиться до необходимых размеров
    	DRL_superPuper_window`;
  • Опять же, всегда даю всем элементам в окне уникальные машинные имена. Т.е., на примере этого кода - всегда дописываю последнюю строчку.
    Таким образом, я всегда могу получить полный путь для любого элемента гуя, сделав, к примеру, так (если я точно знаю, что моё поле находится в лэйауте с именем layout и называется field):
    Код:
    $myField = $window + "|layout|field";
  • Соответственно, любой другой процедуре мне надо передавать только адрес окна. Ну я так и делаю. На все кнопки я вешаю не конкретные команды, а обращение к другой процедуре с передачей адреса окна. Например, так:
    Код:
    button
    	-l "OK"
    	-c ("DRL_superPuper_OKbutton " + $window + ";")
    	OKbutton;
  • А уже в этой, дополнительной процедуре (в примере выше - DRL_superPuper_OKbutton) я собираю полный путь до всех нужных элементов гуя, получаю из них значения (как описал Дима - через флаг -q) и выполняю нужные команды с нужными параметрами.
Очень хороший пример - один из моих старых скриптов. Весь ГУЙ там в процедуре DRL_dispToPoly.
Я не хвастаюсь, сам скрипт уже не актуален. Просто там и всё описанное выше, и вкладки как радиобаттоны, и formLayout (позволяющий всё оч удобно раскладывать), и ещё пара плюшек и коврижек. Первый мой скрипт, для которого я написал человеческий ГУЙ, и поставил себе задачу обкатать всё ГУЕстроение по максимуму. Если что-то будет непонятно - спрашивай, поясню.
 
ай-ай-ай, ай-ай-ай... Но обо всем по порядку:

придётся вешать scriptJob на обновление зависимого поля (со скрипт-джобами я, лентяй, так и не разобрался - так что помочь не смогу).
в любом UI элементе с вводом есть флаг "changeCommand", в котором можно указать mel-код (в т.ч. вызов процедуры), который сработает на изменение в этом элементе. Ничто не мешает написать процедуру, которая получается коэффициент, на которой надо домножить значения в других элементах, и никаких script job не требуется.

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

Код:
 global string $gClipsWindow;
 if (`window -exists $gClipsWindow`)
	deleteUI $gClipsWindow;

 $gClipsWindow = `window
 		-wh 360 500
		-s 1
		-title "Clip Viewer"
		-mxb 0
		-menuBar 1`;
Т.е. по сути я отдаю на откуп Maya генерацию имен для элементов, а сам работаю исключительно с переменными. Поскольку при создании элементов UI Maya возвращает полный путь, никаких ухищрений с дополнением пути (layout, field и прочее) не требуется. Это позволяет спокойно менять UI, не заботясь об изменениях кода по обращению к именам.

На все кнопки я вешаю не конкретные команды, а обращение к другой процедуре с передачей адреса окна.
А зачем? Я не понял, в чем бонус, честно. Если мне надо найти какой-то элемент, у меня есть его глобальное имя.

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

Александр Иванов 97779

Активный участник
Рейтинг
5
DRL, Дима спасибо большое!
Вы реально пишите быстрее чем я успеваю всё переварить =))))

Тема написания интерфейсов очень интересна, примеры были бы очень полезны!
 

Лекс Дарлог (DRL)

Активный участник
Рейтинг
14
changeCommand у меня почему-то не всегда отрабатывал корректно. Я как-то писал простенькое служебное окошко, которое позволяло по-быстрому получить whatIs и runTimeCommand для введённого текста (использую до сих пор). Так вот, пришлось использовать enterCommand. Для radioButtonGrp флаги вида -on1 и -of1 - работают на ура. Но вот именно changeCommand работает некорректно. При каких конкретно условиях - прости, сейчас не вспомню. Я это пробовал давно. Но хорошо запомнил, что в нескольких разных случаях changeCommand мне так и не удалось заставить работать должным образом.

Глобальных переменных я вообще стараюсь по максимуму избегать. То, что внутри скрипта - то внутри скрипта. А чем больше глобальных переменных используешь - тем больше шанс последующих конфликтов с чужими скриптами.
Конечно, я всегда даю им максимально уникальные названия и обязательно добавляю префикс со своим ником. Но никогда не знаешь наверняка, вдруг есть какой-нибудь скрипт под названием "Digital Revolutionary Logic" или типа того, который будет использовать ту же глобальную переменную. Да, шанс маленький, но есть. ИМХО, лучше выпиливать подобные проблемы в зародыше.
Если ты точно знаешь, какие данные и в какую процедуру надо передавать - проще добавить аргумент.

При создании окошка практически исключено, что какой-либо из его элементов поменяет адрес. Так что ничего страшного в том, что я по сути прямо в код кнопок напрямую забиваю, с каким адресом запускать нужную процедуру (по нажатию на кнопку).

А зачем? Я не понял, в чем бонус, честно.
Зачем передавать адрес - описал выше. Зачем именно обращение к процедуре, а не код напрямую - если вкратце, потому же, почему ты в xumi рекомендовал не вписывать сам код, а заводить отдельную процедурку.
По нажатию на кнопку может много чего произойти. Самое элементарное - может потребоваться собрать значения всех нужных полей, на основе этого прогнать какие-нибудь условия, что-то посчитать, и т.п.
Если писать это прямо в коде кнопки - код получится нечитаемым из-за обилия экранирующих слэшей + отсутствия подсветки + спецсимволов.
Мне кажется, гораздо проще и удобней завести отдельную процедуру на активацию кнопки. Кроме самых простых случаев вроде deleteUI, естественно.

А вообще, у меня складывается ощущение, что мы сейчас уже обсуждаем разницу подходов, а не "правильное" и "неправильное" написание гуёв на МЕЛе.
В любом случае, это занятие сейчас обречено: МЕЛ уже изжил себя и готов уйти на пенсию. Так что это рассуждение из серии: как лучше лечить головную боль - пиявками или прямым кровопусканием. В эпоху аспирина.
Сейчас, после недавнего падения акций Autodesk, я вообще всерьёз задумался: не грядёт ли через пару годиков повальный переход всех оставшихся майщиков на другие пакеты. Как показала практика, мало для чего нужен один универсальный редактор, который из коробки толково ни с чем не справляется. Гораздо лучше - туча маленьких тулов и нормальный формат обмена данными. Плюс поддержка питона в каждом из этих тулов. И вообще, в области не-игрового CG всё потихоньку развивается в направлении "Композитинговый софт собирает всё вместе, отдельные софтины должны лишь уметь интегрироваться в него".
Но это уже совсееем другая история...

P.S.: А "ай-ай-ай" - потому что взял моду отписываться в твоём топике, или потому что, по твоему мнению, я неправ?
 

Александр Иванов 97779

Активный участник
Рейтинг
5
Мел на пенсию???? Вот блин, я в Майке всего полгода, а мел уже на пенсию...=(((

Мне снова нужна ваша помощь!

Разобрался с тем как передать параметры из интерфейса через переменные, накидал следующий черновик;

window;
columnLayout;
intField -w 70 -h 20 -ann "введите разрешение"
resField;
button -label "createSnapshot" -command "makeObj()" myBtn1;
showWindow;

proc makeObj() {
$res = `intField -q -value resField`;
uvSnapshot -aa -n "C:/1/outUV.psd" -xr $res -yr $res -r 255 -g 255 -b 255 -o -ff psd;
}


Вопрос - как бы запомнить последнее введенное в поле значение, чтобы оно стояло там после повторного открытия окошка?
Я так понимаю нужно значение из $res подставить флагу -v команды intField?

Но когда прописываю что-то типа:

window;
columnLayout;
intField -w 70 -h 20 -v $res -ann "введите разрешение"
resField;
button -label "createSnapshot" -command "makeObj()" myBtn1;
showWindow;

proc makeObj() {
$res = `intField -q -value resField`;
uvSnapshot -aa -n "C:/1/outUV.psd" -xr $res -yr $res -r 255 -g 255 -b 255 -o -ff psd;
}

Майка ругается что переменная не объявлена...
Как тут быть?
 

Лекс Дарлог (DRL)

Активный участник
Рейтинг
14
Давай отделять мух от котлет. Есть запоминание настроек окошка, а есть передача значений обратно в него.

Сперва про передачу значения.
Помимо флага -q (query) есть ещё флаг -e (edit). Вообще, в МЕЛе в принципе есть 3 режима: create, query и edit. По умолчанию используется первый. Второй позволяет узнать какие-то параметры, а третий - отредактировать.
В ГУИшных командах отредактировать можно почти всё. А в данном случае - значение поля.
Как-то так:
Код:
$res += 1; // Гипотетически предположим, что нам понадобилось увеличить введённое в поле значение на 1
intField -e -value $res resField; // И передать его обратно
Теперь - про сохранение настроек. В Maya есть такая штука - optionVar. Это нативный Майский метод хранения вообще всех параметров. Это особые переменные, которые при каждом сохранении настроек записываются в специальный файл (userPrefs.mel), а при каждом запуске - читаются оттуда.
Соответственно, чтобы запомнить что-то, что будет сохраняться между разными сессиями Майи, надо это записать как optionVar.

Сперва - как надо записывать свои optionVar'ы. Это просто:
Код:
optionVar -intValue "DRL_superPuper_int" 4; // запоминаем переменную типа int
optionVar -floatValue "DRL_superPuper_float" 1.2345; // запоминаем переменную типа float
optionVar -stringValue "DRL_superPuper_string" "Super-Puper!!!"; // запоминаем переменную типа string
Как видишь, синтаксис простой:
optionVar -типЗапоминаемойПеременной "машинноеИмя_Переменной" значение;
Флаги для задания остальных типов переменных ты знаешь где глянуть.

Читать запомненные ранее переменные, как ты уже догадался, можно с помощью флага -q.
Только одно примечание: чтобы избежать ошибок о том, что такая переменная не найдена, надо сперва проверить, есть ли она. Флагом -ex (exists). Как-то так:
Код:
int $qqq = 7; // Создаём переменную $qqq и назначаем ей дефолтное значение
if (`optionVar -ex "DRL_superPuper_int"`) // Если есть такой optionVar
	$qqq= `optionVar -q "DRL_superPuper_int"`; // Считываем его значение в переменную $qqq
Теперь про то, что Майка ругается на необъявленную переменную. Она и будет ругаться. У тебя в коде ты сперва создаёшь окно и в качестве значения поля указываешь какую-то не определённую переменную $res.
А потом, вообще в пределах процедуры, эту переменную объявляешь.

И вообще, тот код, который ты тут написал, не должен работать.
В процедуре makeObj ты читаешь значение из поля resField. Пути в майском интерфейсе считаются относительно текущего выбранного родителя. А если ты банально выделишь вьюпорт - по-моему, родитель поменяется. И Майя там это поле не найдёт. потому что его во вьюпорте и нет. Поэтому в ГУЙ-командах надо вообще всегда использовать полные пути. В данном случае тебе надо запоминать либо путь поля (как предложил Дима), либо путь окна + собирать потом самому путь до поля (как предложил я). Плюс тебе этот путь ещё надо как-то передать в процедуру. Либо в качестве аргумента (как предложил я), либо в качестве глобальной переменной (как предложил Дима).

Кстати, запоминание всех введённых значений у меня в том скрипте, что я кинул, реализовано. И классическая Майская менюха для сохранения/обнуления настроек - тоже. Можешь глянуть там - сразу всё станет понятно.

А про "МЕЛ на пенсию" - это я для Димы написал. Интересно, что он думает по этому поводу. Я в этом не уверен, но, как водится, "терзают смутные сомнения".
 

Александр Иванов 97779

Активный участник
Рейтинг
5
Видимо рано я за запоминание настроек взялся =)
Хорошо, пробую привести код в порядок (на тему использования путей). Не совсем понял как глобальную переменную передать в процедуру.
Вот что у меня получилось (см. изображение), а в ответ, что опять, мол, не объявлена...
 

Вложения

DRL,
"ай-ай-ай" был посвящен предложению про script job, который совсем не соответствовал реальности. Остальные пункты - это действительно разница подходов, а не принципиальных "правильно-неправильно". Я очень рад, что пишу ответы в этом топике не в одиночку, и твои посты - это всегда честно и тщательно проделанная работа, поэтому по поводу них я никогда не скажу "ай-ай-ай".

Касательно Maya|Autodesk в целом - довольно сложно говорить в мировой перспективы и за всех разом, но так уж получается, что Maya вообще не развивается (дописки функционала на уровне плагинов в счет не идут), пакет стоит на месте, и новые фичи типа того же Питона или QT делаются откровенно плохо. Такая ситуация не может длиться вечно, и в какой-то момент, если ничего не изменится, Maya потеряет свой статус. Не знаю, насколько он высокий/невысокий конкретно сейчас, но в целом он явно снижается в пользу владения несколькими специфическими пакетами, чем одним, который, как ты верно заметил, не умеет ничего делать толково из коробки, все надо доделывать до минимально приемлемего состояния. С другой стороны, основные деньги компании приносит корпоративный сектор, которому проще покупать один продукт и искать/содержать под него штат специалистов, чем постоянно поддерживать некий зоопарк софта и экспертов. С третьей стороны, даже корпоративный сектор сейчас меняется и становится все менее централизованным/стандартизированным.

Про MEL : я не понимаю, почему его никак не развивают. В принципе, все, что требуется - это добавить структуры и расширить набор команд работы со строками до уровня Питона или JavaScript. После появления структур в MEL уже можно будет протащить и нативные майские объекты, чтобы работать с ними напрямую, а не через getAttr/setAttr + собранная строка текста, а так же начать задумываться о реализации классов. В этом плане для меня был совершенно удивительным опыт работы с Javascipt в Photoshop, который предоставляет очень простой и понятный способ доступа до объектов, методов и классов. В принципе, довести MEL до уровня Javascript не является сложной задачей, и почему этим не занимаются, мне искренне непонятно. Это могло бы дать вторую жизнь всей майской парадигме, да и очевидно помогло бы более нативно использовать тот же Питон.

Но так же я хочу отметить одну немаловажную вещь: MEL со своей ограниченностью прекрасно подходит для обучения в качестве первого языка и первого опыта работы с графическим пакетом не через пользовательский интерфейс, а со стороны кода. Это существенно расширяет границы восприятия и помогает понять основные подходы, которые потом можно применять в других пакетах, даже не обязательно графических. Если сказать несколько вычурно, то приобретаешь определенную смелость и нахальность - уже без мандража влезаешь документацию для разработчиков, привычно ругаешься на кривизну реализации функционала и методично ищешь решения на форумах. В этом плане, Александр, ты идешь в верном направлении.

Еще одна немаловажная штука Maya и MEL заключается в возможности писать свои интерфейсы и получать реакцию от реальных пользователей. Я уже довольно много лет придумываю разные инструменты, и Maya нередко выступала в виде референса или площадки для реализации/проверки моих идей. Мне сложно разделить свой опыт работы c интерфейсами в С++ Builder|Delphi|Maya|HTML|PyQT|iOS на конкретные части, но Maya явно дала один из основных вкладов в общую копилку.
 

Лекс Дарлог (DRL)

Активный участник
Рейтинг
14
Дим,
Со всем постом согласен от "А" до "Я", аж приятно. :)

Не совсем понял как глобальную переменную передать в процедуру.
Вот смотри.
У тебя любая переменная может быть либо локальной, либо глобальной. Т.е., она существует либо только в пределах той процедуры, где она объявлена, либо вообще везде. Если ты создал переменную прямо в скрипт эдиторе - то она по определению является глобальной. Потому что ты создал её не в какой-то процедуре, а прямо в Майе.
Чтобы явно создать глобальную переменную - надо пользоваться ключевым словом global:
Код:
global int $myInteger;
Тут надо отметить 3 вещи:
  • Глобальную переменную нельзя сразу и создать, и добавить ей значение. Это надо делать по очереди, в 2 строчки.
  • В Майе стандартная практика - это добавлять всем глобальным переменным префикс "g". Т.е., я все мои глобальные переменные называю как-то так:
    Код:
    global int $gDRL_myInteger;
  • Только что неожиданно для себя обнаружил, что иметь как можно меньше глобальных переменных - это официальная рекомендация из доков (ссылка выше). Так что, я бы сказал, создавать что-то глобальное надо только тогда, когда это действительно необходимо. У меня вот сейчас в общей сложности порядка 30 скриптов (да, немного - ведь я обычно в Майе работаю с тем, что есть, а скриптую только в самую последнюю очередь). Ну плюс ещё пачка мелких хаков стандартных майских процедур.
    Так вот, за всё это время мне потребовалось создать всего три глобальных переменных. Одна из них - счётчик timerX, две другие уже не помню. С ними просто ну никак иначе из одной процедуры в другую значение не передашь.
Помимо глобальных/локальных переменных есть ещё глобальные/локальные процедуры. Аналогично, при создании процедуры прямо в скрипт эдиторе, она является глобальной. Но если она описана в скрипте - то вызвать её можно только из этого же скрипта. Либо тоже создавать её как глобальную, тем же ключевым словом:
Код:
global proc my_superPuper_Procedure() {
print "Super-Puper!!!";
}
Соответственно, когда ты весь свой код сохранишь как скрипт, тебе придётся хотя бы одну процедуру в нём сделать глобальной, иначе ты просто не сможешь к ним обратиться. Тут тоже действует такое же правило: чем меньше глобальных процедур - тем лучше. Если ты точно знаешь, что к какой-то процедуре в скрипте ты будешь обращаться только из этого скрипта - оставь её локальной (не дописывай ей global).

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

Ярче всего это видно как раз на примере с гуём.
Любое окошко, которое ты своими скриптами создал, почему-то всегда считается глобальным. И любая процедура, которую оно вызывает, соответственно, тоже должна быть глобальной.
Скажу иначе. Вот у тебя есть скрипт. Вот ты написал в нём процедуру, которая создаёт окно. Вот ты в Майе этот скрипт за'source'ил и вызвал эту процедуру. Вот окошко создалось. Так вот, теперь у тебя любая процедура, которая указана в качестве команды для любого элемента (будь то кнопка или чекбокс или ещё что) - должна быть глобальной. Потому что Майя вдруг взяла и забыла, что это окошко создалось из твоего скрипта. И поэтому ей совершенно по барабану, что процедуры, вызывающиеся по нажатию на кнопку, описаны в том же скрипте. Она требует, чтобы эти процедуры были глобальными - и всё тут.

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

И ещё, раз уж тему процедур задели...
Помимо всего прочего, процедура может возвращать значение.
Код:
global proc string my_superPuper_Procedure() {
string $superPuper = "Super-Puper!!!";
print $superPuper;
return $superPuper;
}
Данный конкретный пример совершенно бессмысленен. Но я взял за практику вообще всегда возвращать что-то полезное. Например, сколько раз она отработала, или какие файлы были созданы, или какие ноды, или какой код ошибки, или целый массив всяких нужных результатов.
Когда ты вызываешь процедуру - тебе ничто не мешает просто заставить её отработать. Но если понадобится - ты всегда можешь запомнить результаты её работы, чтобы в дальнейшем с ними работать как-то ещё. Как-то так:
Код:
string $procedureResult = my_superPuper_Procedure;
Ну и напоследок:
обрати внимание, все переменные, которые ты передаёшь процедуре в качестве аргументов, изменяются не только внутри неё. Как бы сказать иначе? Если ты в коде процедуры как-то изменял значение переданной переменной, то её значение поменяется не только внутри процедуры. Оно поменяется и там, где ты к этой процедуре обращался. Например:
Код:
proc SimpleProc (int $int) {
$int += 1;
}

int $my_superPuper_int = 6;
SimpleProc ($my_superPuper_int);
После того, как этот код отработает, в $my_superPuper_int будет 7. Хотя, казалось бы, мы сами тут его значение не меняли. Но его поменяла процедура.
Это надо иметь в виду.
С одной стороны, чтобы предотвратить изменение переменных, которые были переданы в процедуру, надо первым делом создавать их копии. И уже с копиями работать в процедуре.
С другой стороны - это отличный способ вернуть несколько значений, если нам это требуется. Т.е., что-то самое фундаментальное возвращает сама процедура, а ещё какие-нибудь полезные результаты записываются в некоторые переменные, которые мы передали в качестве аргументов. Думаю, будет проще с примером:
Код:
proc int DRL_useless (string $str, float $resPart, string $resChar)
/* Совершенно бесполезная процедура, которая сама по себе возвращает число символов в строке,
а в 2 последних аргумента записывает всякую хрень: какую часть от длины строки занимает 1 символ и какой символ - первый */
{
int $res = `size $str`;
$resChar = `substring $str 1 1`;
$resPart = 1 / $res;
return $res;
}

string $myString = "Super";
int $myLength;
float $myPart;
string $myChar;

$myLength = DRL_useless($myString, $myPart, $myChar);
// После этого в $myLength - 5, в $myPart - 0.2, в $myChar - "S".
Извиняюсь за такой длинный пост. Я старался охватить все нюансы по теме вопроса, чтобы у тебя сразу в голове всё уложилось структурировано, и не пришлось искать обрывочную информацию тут и там.
 
Сверху