Забыл написать еще об одном очень важном отличии "прямого доступа" от MEL (это отличие следует из написанного выше, но оно не так очевидно). Я написал "прямой доступ" в кавычках, потому что MEL - это более прямой доступ, чем "прямой доступ"

. Попробую пояснить.
При "прямом чтении" атрибута, реально считывается не атрибут, а его копия. Чтение производится со входа экспрешна, куда ПЕРЕД выполнением экспрешна заносится копия атрибута. Т. о., чтобы экспрешн не делал, даже если реальный атрибут, к которому обращается экспрешн, поменяется в процессе выполнения, считываться при "прямом доступе" будет одно и тоже старое значение атрибута, а не сам атрибут. Здесь есть два исключения, но о них - в конце.
При "прямой записи" в атрибут, реальной записи не происходит. Запись производится только в выход экспрешна. Если экспрешн в процессе своего выполнения несколько раз "прямо изменит" какой-нибудь атрибут, реальный атрибут не изменится ни разу. Изменения произойдут только на выходе экспрешна. Копирование результата с выхода экспрешна на реальный атрибут произойдет только ПОСЛЕ завершения работы экспрешна - в процессе дальнейшего пересчета графа (копирование будет производиться в соответстии со связями по графу).
В отличие от "прямого доступа", команда setAttr реально заносит требуемое значение прямо в атрибут назначения и прямо в момент выполнения команды. При этом, пересчета графа НЕ происходит, но все атрибуты, зависящие от измененного атрибута, помечаются недействительными.
Команда getAttr производит реальное чтение атрибута прямо в момент выполнения команды. При этом, если на момент выполнения команды атрибут окажется помеченным как недействиельный, это приведет к пересчету той части графа, которая отвечает за данный атрибут. Это произойдет посередине выполнения экспрешна и может оказаться как полезным (см. пример 2 в моем первом ответе, когда используется нода arcLengthTool), так и вредным. Самое интересное, что в процессе такого пересчета части графа, могут быть запущены другие экспрешны и только после их завершения будет продолжено выполнение первого экспрешна. Совсем самое интересное - в числе этих экспрешнов может оказаться и сам первый экспрешн. В этой ситуации, майка скорее всего зависнет, но точно сказать, что произойдет - не могу.
Теперь об исключениях.
Первое исключение - когда эксрешн "прямо читает" и "прямо записывает" один и тот же атрибут.
Например.
tx=10;
print("tx="+tx+"\n");
tx=20;
print("tx="+tx+"\n");
Такой экспрешн напечатает сначала 10, потом 20. В этой ситуации, входом и выходом экспршна является одна и та же точка (один и тот же атрибут). Вторая команда tx=20 меняет не сам tx, а выход экспрешна, который также является и его входом. Вторая команда print опрашивает этот вход, который изменен командой tx=20 и получает измененное значение tx. Т. о., получили пример, когда "прямое чтение" в процессе выполнения экспрешна дает разные результаты. Тем не менее, реального изменения атрибута tx не происходит ни при выполнении tx=10, ни при выполнении tx=20. И только после завершения работы экспрешна значение с его выхода (которое на этот момент равно 20) копируется по связи графа в реальный атрибут tx.
Второе исключение показывает некорректное обращение с MEL в экспрешне.
Рассмотрим следующий экспрешн:
print("tx1="+xxx.tx+"\n");
if(xxx.tx!=10)
{
setAttr "xxx.tx" 10;
getAttr "xxx.ty";
}
setAttr "xxx.tx" 9;
print("tx2="+xxx.tx+"\n");
xxx.ty=xxx.tx-2;
Как точно будет работать этот экспрешн - сказать трудно. Дома майки нет, проверю завтра на работе. Но возможно, что майка даже не повиснет и произойдет следующее:
(имеется в виду, что перед выполнением экспрешна значение xxx.tx НЕ равно 10).
Перед выполнением экспрешна, на его вход будет скопировано значение xxx.tx, которое не равно 10 по начальным условиям. Допустим, оно равно 9.
Далее, распечатается строка tx1=9
Затем, так как tx!=10, будет запущена ветка if, где значение атрибута tx меняется на 10 (но вход экспрешна остается равен 9).
При этом, майка значет, что от атрибута xxx.tx через экспрешн зависит атрибут xxx.ty. Соответственно, он (ty) помечается недействительным.
Далее идет команда getAttr, которая опрашивает недействительный атрибут.
Здесь майка приостанавливает работу экспрешна, так как для выполнения команды getAttr ей требуется посчитать значение атрибута ty. Для этого она двигается по связи и попадает опять в данный экспрешн.
Майка копирует значение tx на вход экспрешна, которое теперь равно 10 и снова запускает экспрешн.
Здесь появится строка
tx1=10
Затем if будет пропущен и выполнится команда setAttr, которая заносит в tx число 9
Далее будет выведена строка tx2=10 (в принте используется "прямой доступ", т. е. будет распечатано не реальное значение атрибута, а значение входа экспрешна, которое по прежнему равно 10).
Затем, в ty будет занесено значение 8 (10-2=8) и работа экспрешна завершится.
Что произойдет дальше - сложно сказать.
По идее, в этот момент успешно завершается выполнение команды getAttr и экспрешн должен перейти к выходу из конструкции if и к выполнения команды setAttr "xxx.tx" 9;
Но так как за экспрешн отвечает одна нода, внутреннее состояние которой изменилось за счет того, что экспрешн был выполнен второй раз, возможно этого не произойдет.
Но если произойдет, то дальше, будет выведено значение входа экспрешна, которое скорее всего в этом месте будет равно 10, а не 9 (из-за того, что нода только что обрабатывала второй раз экспрешн и последнее, что она занесла в свой вход - было значение 10).
Затем, в ty занесется значение 8 и работа экспрешна завершится.
Т. о., такой экспрешн может вывести следующее:
tx1=9
tx1=10
tx2=10
tx2=10
Возможно, будет выведено все тоже самое, но без последней строки.
А возможно, майка вообще уйдет или как-нибудь еще возмутится на подобное издевательство.