Eccoci alla quarta parte del tutorial di MEL, dove parleremo delle espressioni.

Le espressioni sono un modo molto veloce di controllare gli attributi degli oggetti in Maya. Essenzialmente la sintassi delle espressioni è la stessa di MEL, a parte per una differenza: in un'espressione, infatti, è possibile accedere ai parametri di un oggetto direttamente, mentre in uno script MEL bisogna usare GetAttr o SetAttr.

Ad esempio:

MEL

setAttr polySphere1.radius 4;

ESPRESSIONE

polySphere1.radius = 10;

Per scrivere un'espressione si utilizza l'expression editor, che possiamo aprire in due modi:
a)    dal menu Window->Animation Editors
b)    facendo click con il tasto destro su un qualsiasi attributo di un oggetto nel Channel Box (l'attributo DEVE essere selezionato) e scegliendo Expressions…

L'Expression editor è costituito da varie parti:

ExpressionEditor

In alto vediamo gli oggetti selezionati ed i loro attributi. Notare che non è necessario selezionare un oggetto per scrivere un'espressione che riguardi quell'oggetto, la lista degli oggetti/attributi è solo per comodità.

Se dal menu Select Filter scegliamo "By Expression Name" invece di "By Object Name" invece di vedere gli oggetti selezionati vedremo i nomi delle varie espressioni che abbiamo creato. Questo è utile per modificare delle espressioni dopo che le abbiamo scritte (altrimenti possiamo sempre aprire l'Expression Editor facendo click con il tasto destro dal channel box su un attributo collegato a quell'espressione e l'espressione sarà selezionata in automatico).

Farò adesso tre esempi di utilizzo delle espressioni.

INGRANAGGI


In questo esempio animeremo degli ingranaggi.

Questa è la nostra scena iniziale:

ingranaggi

I tre ingranaggi si chiamano, con molta fantasia, Ingranaggio1, Ingranaggio2 e Ingranaggio3.

Apriamo l'expression editor e scriviamo:

Ingranaggio2.rotateY = -Ingranaggio1.rotateY;
Ingranaggio3.rotateY = Ingranaggio1.rotateY;

Diamo un nome all'espressione e clicchiamo Create.

Ora ruotiamo Ingranaggio1 su Y e… il gioco è fatto! Semplice, no?
In pratica abbiamo detto all'ingranaggio 2 di ruotare all'opposto di 1 e al 3 di ruotare come l'1 (cioè all'opposto di 2).

Ora, però, visto che siamo pigri… non vogliamo animare a mano ingranaggio1.

Riapriamo l'expression editor e dal menu Select Filter scegliamo By Expression Name.

Selezioniamo la nostra espressione e modifichiamola così:

Ingranaggio1.rotateY = frame;
Ingranaggio2.rotateY = -Ingranaggio1.rotateY;
Ingranaggio3.rotateY = Ingranaggio1.rotateY;

Aggiorniamo l'espressione usando il bottone Edit, premiamo play e gustiamoci l'animazione!

frame è una keyword speciale che possiamo usare nelle espressioni e che vale come il frame corrente. Quindi in questo modo Ingranaggio1 farà 1 giro in 360 frames.
Una keyword simile è time che vale come il tempo corrente (non il frame) sulla timeline.

Supponiamo ora di voler controllare la velocità dell'ingranaggio.
Selezioniamo Ingranaggio1 e nel Channel Box scegliamo Channels->Add Attribute.

Ci apparirà una finestra chiamata Add Attribute, che riempiremo così:

addattr

Ovviamente i valori 0 e 10 sono assolutamente arbitrari, potete metterne anche altri a vostro piacimento.

Ora riapriamo l'expression editor e modifichiamo la prima riga in questo modo:

Ingranaggio1.rotateY = frame * Ingranaggio1.Velocita;

Ed il gioco è fatto! Ora gli ingranaggi girano da soli e possiamo anche modificarne (e mettere dei keyframes) sulla velocità!

Note:
  • ricordarsi che i nomi degli attributi sono case-sensitive: Velocita è diverso da velocita
  • nonostante sia possibile mettere l'accento nel nome dell'attributo ho notato che poi l'espressione dà errore.
  • in questo caso è utile usare un valore float per la velocità, in modo che sia possibile aumentarla gradualmente e non a step come succede usando un int.
E questa è la scena finale.


SCHELETRO

Un'altra situazione in cui comunemente può essere utile usare le espressione è il movimento di uno scheletro.
Ad esempio, è noioso dover spostare i piedi e il bacino per far camminare il nostro personaggio… se il bacino si spostasse da solo sarebbe meglio!

Possiamo fare questo facilmente con un'espressione.
Ecco la scena iniziale da cui partiremo.

skeleton

Lo scheletro non è nulla di speciale, ma vorrei far notare 2 cose:
1)    gli IK handle dei piedi hanno un point constraint ai due controlli poligonali, in modo che se abbassiamo il bacino i piedi rimangano in terra. Inoltre possiamo spostare gli oggetti per muovere il piede.
2)    Il bacino (osso che ho chiamato root) e' stato raggruppato in un gruppo (chiamato skel). Questo è indispensabile per qualcosa che vedremo in un attimo.

Benissimo, apriamo l'expression editor e cominciamo a scrivere:

skel.translateX = (piedeSxHandle.translateX + piedeDxHandle.translateX)/2;
skel.translateZ = (piedeSxHandle.translateZ + piedeDxHandle.translateZ)/2;

Con questa semplicissima espressione andiamo a centrare le posizioni X e Z del bacino al centro rispetto al movimento dei piedi.
Notare che se non avessimo il point constraint sui piedi, muovendo il bacino si muoverebbero anche i piedi di conseguenza… e avremmo risultati non troppo utili! Provare per credere!!!

Inoltre è importante notare che non stiamo muovendo direttamente l'osso root, ma stiamo muovendo il gruppo. Questo ci lascia la possibilità di prendere root e muoverlo a nostro piacimento, potendo così spostare il baricentro dello scheletro se necessario, come possiamo vedere qui sotto (gif animata, ci potrebbe mettere un po' a caricare):

movimbacino

Possiamo sbizzarrirci a mettere altri controlli, ad esempio potremmo voler ruotare il corpo in una direzione o nell'altra a seconda di quale piede è più avanti.
Aggiungiamo alla nostra espressione:

skel.rotateY = (piedeDxHandle.translateZ - piedeSxHandle.translateZ) * 2;

Questa espressione essenzialmente ruota lo scheletro di un numero di gradi positivo se il piede destro è avanti (quindi ha z maggiore del piede sinistro), negativo in caso contrario.
Il 2 è un parametro assolutamente empirico che serve per enfatizzare un po' il movimento, potete aggiustarlo come volete, si potrebbe addirittura aggiungere un attributo allo scheletro per governare questo parametro. Ovviamente valori maggiori daranno un effetto molto più marcato. Ovviamente tutto questo funziona se il nostro personaggio sta camminando sull'asse Z!

Supponiamo ora di voler usare queste espressioni per gran parte della nostra scena, ma non ad esempio in un certo punto in cui il nostro personaggio fa un movimento "strano".

Possiamo semplicemente aggiungere un attributo a skel (o ad un qualsiasi altro oggetto nella scena) che governerà l'uso o meno delle espressioni.

Selezioniamo quindi skel, e nel channel box facciamo Channels->Add Attribute e aggiungiamo un Boolean (cioè 0/1, o on/off se preferite) chiamato espressioni.

A questo punto modifichiamo la nostra espressione in:

if (skel.espressioni)
	{
	skel.translateX = (piedeSxHandle.translateX + piedeDxHandle.translateX) /2;
	skel.translateZ = (piedeSxHandle.translateZ + piedeDxHandle.translateZ) /2;
	skel.rotateY = (piedeDxHandle.translateZ - piedeSxHandle.translateZ) * 2.5;
	}

Quindi, se espressioni è on le espressioni funzioneranno, altrimenti no! Semplice vero?
Ovviamente espressioni simili si possono anche fare per le braccia, e scheletri più complessi possono richiederne delle altre.

LET THERE BE LIGHT!

L'ultimo esempio che vedremo riguarda questa scena:

machineoff

Girando la manopola andremo ad accendere via via i diversi led e la lampadina si illuminerà sempre di più, come potete vedere in questa serie di immagini (click x ingrandire):

machineworkingthumb

L'idea anche qui è molto simile alle precedenti

Abbiamo un attributo "Accensione" che va da 0 a 9 e che ho messo su di un locator (ma, ovviamente, si può mettere dovunque).

I 9 led hanno 9 shader diversi, chiamati PhongLed1, PhongLed2 etc. etc.
Questa è l'espressione che utilizzo:

manopola.rotateY = -36 * controller.Accensione;

filamentolamb.incandescenceR =
filamentolamb.incandescenceG =
filamentolamb.incandescenceB =
0.11 * controller.Accensione;

filamentolamb.glowIntensity = 0.22 * controller.Accensione;
luceLampadinaShape.intensity = 0.11 * controller.Accensione;

for ($i=1; $i<=controller.Accensione; $i++)
   {
   $cmd = "setAttr PhongLed" + $i + ".colorR 1";
   eval ($cmd);
   $cmd = "setAttr PhongLed" + $i + ".incandescenceR 0.8";
   eval ($cmd);
   $cmd = "setAttr PhongLed" + $i + ".incandescenceG 0.1";
   eval ($cmd);
   $cmd = "setAttr PhongLed" + $i + ".glowIntensity 0.05";
   eval ($cmd);
   }

for ($i=controller.Accensione+1; $i<10; $i++)
   {
   $cmd = "setAttr PhongLed" + $i + ".colorR 0.1";
   eval ($cmd);
   $cmd = "setAttr PhongLed" + $i + ".incandescenceR 0.0";
   eval ($cmd);
   $cmd = "setAttr PhongLed" + $i + ".incandescenceG 0.0";
   eval ($cmd);
   $cmd = "setAttr PhongLed" + $i + ".glowIntensity 0";
   eval ($cmd);
   }

Nonostante sia un po' lunga non c'è nulla di molto complesso!
Il tutto gira attorno al valore dell'attributo Accensione.
La manopola viene ruotata di 36 gradi per ogni unità di Accensione.
L'incandescenza e il glow del materiale del filamento sono dipendenti dallo stesso attributo e stesso dicasi per l'intensità della luce all'interno della lampadina.

Per quanto riguarda i led la cosa è un attimo più complessa nel senso che facciamo un ciclo for prima da 1 a Accensione e poi da Accensione + 1 a 9.
Con il primo ciclo for "accendiamo" i primi led, con il secondo spegnamo gli altri,
anche qui semplicemente cambiando colore, incandescenza e glow.

Notare che poiché stiamo "costruendo" il nome dell'oggetto su cui andare a lavorare (usando PhongLed + $i), in questo caso dovremo usare la sintassi MEL e usare setAttr.

E questo è tutto anche per questa parte! Nella prossima parte spiegherò come creare un'interfaccia per uno script MEL.

Ciao!

---
Questo articolo è stato importato automaticamente dal forum il 31/lug/2014
Per vedere il post originale e/o i commenti sul forum prima di quella data clicca qui