Aide pour After Effect, techniques, expressions.

mardi 22 janvier 2008

EXPRESSIONS : linear

linear.

Cette fonction crée une variable en fonction d'une autre.
Par exemple, on veut que lorsque X varie de 0 à 50 alors Y varie de 6 à 2. Cela peut servir à plusieurs choses:
-quand la position sur Z d'un calque 3d varie, l'opacité du meme calque varie.
-plus un calque est transparent, plus il est flou.
etc.

Voilà la synthaxe:

Y=linear ( X , a , b , A , B )

Il y a beaucoup de chiffres, mais rien de compliqué :
X est la valeur qui varie.
a et b sont les valeurs entre lesquelles X varie.
A et B sont les valeurs entre lesquelles Y varie.

exemple :

X=time;
Y=linear (X , 0 , 50 , 6 , 2 )

je mets volontairement des espaces autour de chaque chiffre et virgule, car on a vite une ligne riche en information. Quand on écrira des lignes du type
linear (x,incr-1,incr*(index+2),math.abs(math.sin(time*360)),100)

L'exemple est extrème, mais il montre bien que se faire une ligne lisible est important pour modifier quoi que ce soit par la suite, ou meme eviter d'oublier une virgule ou une parenthèse.

Lorsque X vaut 0, Y vaut 6 et quand X vaut 50, Y vaut 2. Quand X prend les valeurs intermédiaire, Y prend ses propres valeurs intermédiaire. Par exemple, quand X vaut 25, Y vaut 4.
Que se passe-t-il quand X vaut plus de 50 ? Et bien Y est "bloqué" à 2. Et quand V vaut moins de 0, Y est "bloqué" à 6.

a,b, A et B peuvent évidemment aussi etre des variables comme nous le verrons plus tard.

L'utilisation de linear est tres large, on s'en sert dans de nombreux cas.
linear peut etre remplacé par un autre mot : ease.
La synthaxe est la meme, mais l'effet diffère très légèrement:
Avec ease, la valeur Y aura une accélération au début et une décélération à la fin, à la façon d'une clef "lissage de vitesse", "ease" en anglais.
easeIn permet une accélération au début, et une fin linéaire.
easeOut permet une décélération à la fin, et un début linéaire.

























J'appliquerai cette fonction très souvent, vous en découvrirez donc plein d'utilités.

EXPRESSIONS : moyenne

Ici, pas de nouvelle fonction, juste un tout petit calcul de rien du tout.
Nous cherchons à ce qu'un objet soit toujours entre deux autres, plus précisement au milieu de ces derniers.











Rien de plus simple, certains s'en souviennent peut etre, ils sagit de la somme des postions des deux objets, divisée par 2.

Créez 2 solides bleus et un solide rouge. Ouvrez les positions des 3, et créez une expression pour le rouge.

a=thisComp.layer("Bleu roi uni 3").transform.position;
b=thisComp.layer("Bleu roi uni 2").transform.position;

(a+b)/2

Voilà, meme pas la peine d'expliquer les 3 lignes, ça tombe sous le sens, et ça s'écrit en 5 sec.

Nous pouvons également rajouter un lookAt, pour que le carré rouge soit toujours dans l'axe des deux autres. Passez le calque en 3d, créez une expression pour son orientation, et recopiez les deux 1ere ligne de l'expression de position:

a=thisComp.layer("Bleu roi uni 3").transform.position;
b=thisComp.layer("Bleu roi uni 2").transform.position;

et rajoutez

lookAt ( a , b )

Vous aurez surement à reajuster la rotation Y de 90 degrés, et voilà.



EXPRESSIONS : lookAt

LookAt, ça va être simple à expliquer:












Cette fonction simplissime sert à donc à ce qu'un objet soit aligné avec un ou deux objets. Très pratique. Voilà comment on s'en sert.
Tout d'abord, votre calque doit être un calque 3d, car l'expression est faite pour "orientation" et non la rotation.
Créez deux calques, l'un carré l'autre en forme de barre, passez la barre en mode 3d, ouvrez son orientation, et écrivez ceci:

lookAt (

Comme d'habitude, le deuxieme mot des fonctions commence par une majuscule. La synthaxe est la suivante : lookAt ( A, B ) , ou A et B sont les positions respectives de deux objets. Si l'une des deux positions est celle de l'objet "barre", alors l'objet tournera sur son axe. Si les deux positions sont celles de deux autres objets, la barre s'orientera sur l'axe parallele à l'axe des deux objets.

Reprenons notre expressions
lookAt ( . Placez le curseur apres la parenthese, prenez la corde, attachez la à la position de l autre objet, mettez une virgule, et écrivez position.

On se retrouve donc avec quelque chose qui ressemble à ça:

lookAt( thisComp.layer("Rouge uni 2").transform.position , position )

C'est finalement très simple, il suffit juste de donner les deux positions qu'on souhaite pointer. Il ne vous reste plus qu'à modifier le point d'ancrage de la barre si besoin est. Sur mon exemple, le point d'ancrage est à l'extrémité de l'objet et non en son centre comme initialement.

A noter que l'objet s'alignera, mais pas forcément dans l'axe que vous désiriez. Pour réajuster l'axe, utilisez les rotations X Y Z. (qui sont tjs animables si besoin est).

Il peut arriver qu'on ne veuille pas que le calque soit en 3d. Par exemple, si une camera est présente dans votre scene, le passage en 3d du calque change sa position dans la composition.
Nous verrons plus tard comment orienter un objet sans qu'il soit en 3d, c'est un peu plus compliqué.

samedi 19 janvier 2008

EXPRESSIONS : les mouches

Première application concrète des expressions dans AE ! (ici en tout cas).
Car oui, le but des expressions n'est pas juste de faire joujou avec les chiffres, mais bien de les intégrer dans vos animations.

voilà ce que nous allons faire:












Oui, ce post est long, mais ça n'est pas parce qu'il est compliqué.
Je ne vais pas balancer les lignes magiques directement, mais plutot expliquer la démarche qui consiste à partir d'une volonté d'animation, et trouver le meilleur moyen de la gerer dans AE.

Créez tout d'abord votre cible, que vous appelerez d'ailleurs "cible".
Créez une mouche (un petit solide) qui vous appelerez "mouche01".

Réfléchissons à ce que nous voulons faire. Nous voulons qu'un essaim de mouche suive un objet, avec donc un mouvement général de l'essaim (large), plus un mouvement propre à chaque mouche(frénétique). Chaque mouche suit l'objet avec plus ou moins de retard.

Créez tout d'abord un null objet (ctrl alt shift Y), qui va nous permettre de stocker toutes les valeurs que l'on veut faire varier. Nous voulons que les mouches aient un retard compris entre 5 images et 30 images sur l'objet cible.

Créez donc deux paramètres glissière au null, appelez la 1ere "max" et la 2eme "min"; dans "min", tapez donc 5, et 30 dans "max".

Chaque mouche aura également sa propre frénésie. La frénésie sera bien évidemment un futur wiggle. Nous ne ferons varier que l'amplitude pour la raison suivante: Nous voulons qu'il y ait des mouches plus ou moins frénétiques. Donc si nous faisons varier uniquement l'amplitude avec une fréquence fixe, chaque mouche va faire varier sa position avec la meme fréquence, donc plus l'amplitude sera forte, plus la mouche sera frénétique. C'est suffisant pour visualiser des mouches toutes différentes.

Créez donc deux autres parametres glissiere sur le null, un "amp max" et un "amp min".
amp max =60 , amp min = 10

Voilà pour les variables de réglage.

Ouvrez la position de la mouche, et c'est parti pour la création des variables:
(comme vous pouvez le voir, " //" permet de rajouter du texte dans les expressions qui ne sera pas lu par AE, pratique pour rajouter des annotations personnelles.

p=thisComp.layer("cible").transform.position; // position de la cible
min=thisComp.frameDuration*thisComp.layer("Nul 1").effect("min")("Curseur");
max=thisComp.frameDuration*thisComp.layer("Nul 1").effect("max")("Curseur");
amin=thisComp.layer("Nul 1").effect("amp min")("Curseur");
amax=thisComp.layer("Nul 1").effect("amp max")("Curseur");


Pour min et max, nous avons multiplié la valeur de la variable du null par la durée d'une image dans la composition (
thisComp.frameDuration). min vaut 5 et max vaut 30. Donc le retard sera compris entre 5 images et 30 images.

Si nous avions juste écrit ceci:

min=thisComp.layer("Nul 1").effect("min")("Curseur");
max=thisComp.layer("Nul 1").effect("max")("Curseur");

le retard aurait été compris entre 5 et 30 secondes comme nous le verrons apres.

Ca, c'est fait.
Nous voulons donc que chaque mouche ait sont propre retard.
Définissons ce retard:

seedRandom(index,true); //
permet donc d'avoir par la suite une valeur au hasard fixe. R=random(min,max); // crée donc une variable R égale à une valeur fixe au hasard entre min et max, 5 et 30 images donc pour nous. Si votre compo est à 25 im/s, R varie donc entre 5*(1/25) et 30*(1/25), donc entre 0.2 sec et 1.2 sec.

Maintenant, la frénésie propre à chaque mouche:

A=random(amin,amax); //crée une variable A égale à une valeur fixe au hasard entre amin et amax, donc entre 10 et 60 (le seedRandom est toujours actif)
w=wiggle(5,A);// notre wiggle sera différent pour chaque mouche, entre (5,10) et (5,60)

Récapitulons, pour le moment nous avons ceci:

p=thisComp.layer("cible").transform.position;
min=thisComp.frameDuration*thisComp.layer("Nul 1").effect("min")("Curseur");
max=thisComp.frameDuration*thisComp.layer("Nul 1").effect("max")("Curseur");
amin=thisComp.layer("Nul 1").effect("amp min")("Curseur");
amax=thisComp.layer("Nul 1").effect("amp max")("Curseur");

seedRandom(index,true);

R=random(min,max);

A=random(amin,amax);

w=wiggle(5,A);

Rien de bien particulier, nous avons créé 5 variables: la position de la cible, et 4 variables venant des paramètres glissière du null.
Ensuite, R définie le retard en seconde, A la frénésie de la mouche.

Passons à la dernière ligne, celle qui va définir la position avec toutes ces variables. Soyons méthodiques :

p.valueAtTime(time-R)

voilà le début de la ligne. On demande donc que la mouche ait la meme position que la cible, avec un retard dans le temps vallant R. Rappelez vous, time est en seconde, donc il faut que R soit également en seconde pour une bonne compréhension de la ligne. Voilà pourquoi nous avons créé des variables min et max avec thisComp.frameduration*5 et *30. Nous aurions aussi pu avec des valeurs comme min=0.1 et max =1.2 pour avoir directement des valeurs en seconde. Ici, c'est un choix personnel qui nous permet de connaitre tres precisement le retard en nombre d'images. en général, la fréquence étant 25images/sec, il est facile de calculer ce que l'on veut.

Animez votre cible, et dupliquez plusieurs fois votre mouche. Deja, les mouches suivent avec plus ou moins de retard la cible.










Effacez toutes les mouches, sauf une. Réouvrez sa position, et reprenons la suite de

p.valueAtTime(time-R)

Rajoutons la frénésie:

p.valueAtTime(time-R)+W

Et là, vous observez un petit souci, la mouche se décale dans l'espace. Et oui, souvenez vous, le wiggle a cette particularité qu'il contient déja la position de l'objet, pour des raisons très logique que j'ai déja expliqué. Donc nous devons écrire ceci:

p.valueAtTime(time-R)+W - position

L'effet est le suivant: on rajoute la frénésie du wiggle, mais en enlevant la position contenu en lui en la retirant derriere (position faisant évidemment référence à la position de l'objet).

Redupliquez votre mouche plusieurs fois, animez. hop, ça marche pas trop mal tout ça, chaque mouche a son propre retard et sa propre frénésie. Tout ceci est largement suffisant pour observer des mouches qui ont toutes un comportement tres différent.

Rajoutons le mouvement général de l'essaim. Pour ceci, ouvrez la position du null qui contient toutes les variables, et écrivez ceci:

wiggle(.5,20)

c'est à dire un leger mouvement tres lent ( 0.5 est une fréquence très lente). Ensuite, placez le null à la position [0,0]. Ainsi, sa position va varier entre [-10,10] et [10,10]

Effacez toutes les mouches sauf une, et ajoutez à la dernière ligne ceci:

p.valueAtTime(time-R)+W + thisComp.layer("Nul 1").transform.position

Ainsi, toutes les mouches auront en plus de leur frénésie un mouvement commun, celui du null. Sinon nous n'avions pas replacer le null sur [0,0], le null serait resté au milieu de la composition avec une position du type [200,200] + son wiggle, les mouches auraient donc récupéré toute cette postion en plus.
A noter également qu'au début de l'expression on aurait pu créer une variable :

P=
thisComp.layer("Nul 1").transform.position;

Et ensuite rajoutez ceci à la fin:

p.valueAtTime(time-R)+W+P-position

Et voilà, dupliquez votre mouche une dizaine de fois par exemple, activez le motion blur pour tout le monde et activez le aussi dans la composition (le mouvement des mouches sera moins saccadé en raison de leur rapidité) et lancez l'animation.

Au final, il ne suffira que de modifier l'animation de la cible, et /ou des 4 variables, et toute l'animation suivra.

Avec un peu d'habitude, cette expression ne prendra pas plus d'une minute à mettre en place, pour ensuite avoir un outil d'animation pratique et rapide à modifier. Impossible d'étre aussi maleable et reactif avec des clefs.

Cette animation simpliste est une base qui peut etre affinée à volonté, en voici quelques exemples:

Puisque les mouches vont vers la cible, il peut également etre interessant de jouer sur la distance qui les sépare grace à la fonction "length".
Par ex, plus les mouches sont proches de la cible, plus la cible devient rouge et tremble.

On peut aussi rajouter un leger wiggle tres lent sur leur échelle, pour simuler un déplacement sur l'axe de la profondeur.

Evidemment, tous mes exemples se font avec des carrés, il va de soi que l'uilisation de "vrais" calques changent tout.

voilà voilà.

vendredi 11 janvier 2008

EXPRESSIONS : valueAtTime

ValueAtTime.

Derrière ce nouveau barbarisme se cache encore une fois un nouvel ami pour vous. Et encore une fois, impossible de le remplacer correctement avec les clefs.
Sa fonction est très simple; tout comme son nom l'indique, ValueAtTime permet de creer une variable qui a la meme valeur qu'une autre, mais à un moment différent.

Imaginons ceci: deux solides, avec l'un des deux qui a comme position celle de l'autre solide. Animez ce dernier, l'autre calque se déplace aux memes endroits, au meme moment. Les deux calques seront logiquement superposés.

A présent, effaçons la ligne dans l'expression de position, et écrivons ceci:

p=thisComp.layer("Rouge uni 1").transform.position; (mon "rouge uni 1" ne regarde évidemment que moi ici)
p.valueAtTime(time-1);

Animez le premier solide (l'autre donc) sur plusieurs seconde, et lancez l'animation: le second solide fait exactement la meme chose que son voisin, mais avec une seconde de retard.










C'est finalement assez simple, mais décortiquons quand meme tout ça.
La 1ere ligne ne fait peur à personne, on demande à ce que p soit égale à la position [x,y] de l'autre calque.
Si l'on écrivait p à la ligne suivante, nous aurions deux solides qui feraient exactement la meme chose. Mais p.valueAtTime(time-1); demande à ce que la position de ce calque soit égale à p non pas à l'instant présent, mais à time - 1 c'est à dire à une seconde de retard, time ayant la seconde comme unité. Par exemple, à la seconde 3, AE ira cherche la position que le calque avait à la seconde 2. time - .5 creera un retard d'une demi-seconde, time+3 creera une anticipation de 3 seconde, bouleversant ainsi la causalité universelle.
Comme vous vous en doutez, on peut également avoir time - x, où x varie. On peut également écrire valueAtTime(x) , nous verrons des cas où cela peut etre utile.

Encore une fois, faites bien attention à ce que vous écrivez, et rappelez vous de cette règle:

Pour toutes les fonctions composées de plusieurs mots, tous les mots sont attachés, et chaque nouveau mot commence par une majuscule, sauf pour le 1er mot. valueAtTime. Si vous faites la moindre faute à ce niveau, AE ne reconnaitra pas le mot.

Nous allons à présent creer une expression avec non pas une mais DEUX fonctions. Oui oui, vous allez voir. Nous allons donc utiliser la fonction valueAtTime, et index.

Souvenez vous, index crée une valeur qui correspond à la position du calque dans la timeline.

Créez un solide rouge de 30 par 30, et nommez le "chef".
Créez un solide bleu (ou autre, je m'en fous) de 15 par 15, et nommez le "mouton01", et plaçez le au dessus de chef.
Ouvrons sa position, p= , et hop la corde:
p=thisComp.layer("chef").transform.position;
dec=thisComp.frameDuration;
p.valueAtTime(time - dec*index)

Alors alors, qu'a-t-on fait... La 1ere ligne, facile. Ensuite, nous avons demandé que dec soit égal à la durée d'une image. Et oui, c'est le rôle de
thisComp.frameDuration. Voyons ce doux mot composé. thisComp fait évidemment référence à un paramètre de la composition. Il y en a évidemment plusieurs : sa largeur, sa hauteur, son nombre d'image à la seconde... C'est cette dernière qui nous interesse ici. La durée d'une image. Si votre composition est à 25 image/sec, vous auriez pu écrire dec=1/25.

Notez également le " . " entre chaque mot. le " . " est présent dans tous les mots composés, c'est une sorte de séparateur de hierarchie, tout comme dans p.valueAtTime : on fait les choses dans l'ordre. D'abord on parle de p, ensuite on dit que l'on veut la valeur à un temps différent.
C'est pareil ici: on parle de la composition, et on en demande un sous-paramètre.

Bref, nous avons à présent une variable qui égale au temps d'une image, en seconde. Si votre composition est à 25 images/seconde, votre dec vaut donc 0.04.

p.valueAtTime(time - dec*index)
Ici, on peut facilement déduire ce qu'il se passe. On demande à mouton qu'il suive chef avec un retard dans le temps égale à dec*index, soit ici 0.04 sec puisque son index vaut 1 (c'est pour cela que nous l'avons placé au dessus de chef tout à l heure).

A présent, dupliquez le calque mouton ( crtl D ou pomme D) plusieurs fois.
Lancez l'animation, miracle, les moutons se suivent à la queue leu-leu, avec un décalage d'une image entre chacun. C'est tout à fait logique, le second calque accuse un retard de 0.08 étant donné que son index vaut 2, etc.










Ce retard d'une image est trop faible, augmentons le proprement.
Effacez tous les moutons sauf un. Qu'importe lequel, puisqu'il sont tous des copies conformes.
Nous allons creer une variable qui determinera le retard de chaque calque.

Selectionnez le calque chef, et rajoutez lui le filtre "parametre glissière", dans "option pour expression" dans "filtre". Nommez cette glissière "coeff". Donnez la valeur de 10 à la glissière.
Revenez à votre mouton, et rajoutez cette ligne:
R=thisComp.layer("chef").effect("coeff")("Curseur"); grace à la code bien entendu, sauf pour les inconditionnels du clavier.
Nous allons donc à présent rajouter cette variable à la dernière ligne:
p.valueAtTime(time - dec*index*R)
A present, le retard sera donc égal à une image, multiplié par la position du calque dans la timeline, multiplié par notre coefficient. Ici nous avons 10, donc chaque mouton aura un retard de 10 images par rapport au mouton précédent.










Nous aurions aussi pu taper ceci:
p.valueAtTime(time - dec*index*10)
Le résultat aurait été le meme, sauf qu'ici, si on veut changer la valeur de retard, il faut le faire sur tous les moutons, un par un... Imaginez vouloir changer le retard sur 200 moutons, impossible.
C'est ici un point extrèmement important :
Prévoir les valeurs qu'on voudra peut etre faire varier et régler dans le futur, et creer les variables en conséquence, indépendantes des calques concernés. Aidez vous, ne vous tirez pas une balle dans le pied. C'est également pour cela que nous avons creer la glissère "coeff" sur le chef, et non sur le mouton. Si le "coeff" etait sur le mouton, chaque mouton serait allé chercher son propre coeff, et la glissièere aurait donc été parfaitement inutile. Oui, certains me diront qu'écrire *10 prend une demi-seconde, creer une filtre glissère, creer la variable et taper *R prend 10 sec... Certes, mais vous gagnerez non seulement un grand nombre d'heures, mais votre travail sera meilleur: Plus un réglage est accessible et rapide, plus vous vous permetterez d'affiner votre travail.


Voilà pour valueAtTime, c'est une fonction très important, et infaisable avec des clefs (amusez vous à copier des clefs et les déplacer dans le temps, c'est vite lassant, et surtout, c'est n'importe quoi).
Bien évidemment, et comme d'habitude, cette fonction peut s'appliquer à n'importe quelle valeur dans AE, nous la retrouverons extremement souvent, et notamment dans le prochain post, qui sera ENFIN le premier exemple concret de l'utilisation des expressions.

à vos solides.

vendredi 4 janvier 2008

EXPRESSIONS : random

RANDOM. En anglais, cela signifie hasard. Cette fonction va nous permettre de creer un ou plusieurs chiffres complètement au hasard. Plongeons nous dans le concret:

On crée une composition de 600 x 400, on fait un solide de 50 x 50, on ouvre sa position, et ecrit ça:
X=random ( 0 , 600 );
Y=random ( 0 , 400 );
[ X , Y ]

Lançons l'animation; a chaque image le calque se place à une position différente.
X=random ( 0 , 600 ); cette ligne demande donc à ce que X varie entre 0 et 600.

Voilà les autres possibilités:
random ( [0,0,0 ] , [0,3,5 ] ) : cela va donc creer une variable à 3 dimensions fluctuant entre les deux valeurs. A noter que lorsqu'une des "extrémités" est égale à 0, on peut ne pas la noter:
random ( [0,3,5] ) correspond à la meme ligne que la précédente.

random ( ) : la valeur fluctue de 0 à 1.

Un point important: dupliquez ce calque, et lancez l'animation. Le clone n'a pas la meme position que l'original:
random creer une valeur différente pour chaque calque.

A présent, imaginons qu'on veuille une valeur au hasard, mais fixe; on ne veut pas que la valeur change à chaque image. Nous devons rajouter une ligne:

seedRandom ( 5,true );

Oula, qu'est ce que c'est que ce truc immonde qui ressemble à de la programmation !!!
On se calme, et on regarde. La fonction seedRandom est à intégrer avant la fonction random, car c'est elle qui demande à ce que le random soit fixe ou pas.

( 5 , true ) :
le chiffre 5 a été bien evidemment choisi au hasard ici. Imaginez que la fonction random possède une liste infinie de suites de chiffres. Le chiffre 5 appel donc la liste numero 5.
En gros, ça veut dire que si vous remplacez 5 par 8, la fonction random crachera d'autres chiffres aux hasard. Remettez 5, vous retrouvez les memes chiffres qu'auparavant.
true : il demande à ce que la prochaine ligne "random" soit une valeur fixe.

donc si vous écrivez ceci:
seedRandom ( 5,true );
X=random (0,600);
Y=random (0,400);
[X,Y]

Notre calque prend bien une position au hasard, mais s'y tient. Dupliquez le calque, la copie est ailleurs.

Dans le cas d'un random non fixe, il faut bien comprendre la différence avec wiggle: random crée une valeur différente pour chaque image sans aucun lien avec la valeur sur l'image précédente, alors que wiggle crée 'une courbe" de valeur aléatoire.

EXPRESSIONS : index

INDEX : un mot très important, oui, je sais, je dis ça à chaque fois.

Ce mot bien particulier donne une valeur précise: la position du calque dans la timeline. Et oui... Mais à quoi ça sert ? A tout, nous le verrons au fur et à mesure, c'est une fonction essentielle.
Par exemple, le calque tout en haut de votre composition aura un index égale à 1, etc. Cela nous amène donc à une possibilité extremement importante, celle d'avoir un comportement différent pour plusieurs calques qui sont pourtant de parfaits clones.
Voyons quelques exemples:

Créez un calque de 20x20, ouvrez sa position, et écrivez ceci:
[ index*40 , 100 ]

Votre calque se place naturellement à la position [40 , 100 ]
A present, dupliquez ce calque plusieurs fois ( ctrl D ou pomme D ). A chaque duplication, le nouveau calque se place à la droite du précédent. On le comprend bien, le second calque se place donc à la position [ 2 x 40 , 100 ], donc [ 80 , 100 ], etc.

Nous utiliserons index extremement souvent: pour placer des objets sur une grille, sur un cercle, en ligne, ou pour que chaque calque possède une variable aléatoire propre.