Aide pour After Effect, techniques, expressions.

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à.

11 commentaires:

  1. hey salut très cher freelance Saucisse!

    J'aime le ton, j'aime les explications simples et claires, super blog!

    RépondreSupprimer
  2. par contre un truc, j'ai pas compris pourquoi l'expression finale etait pas


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

    J'ai testé chez moi et ca marchait que avec le - position

    et au passage sur mon null j'ai collé ca sur la position :

    w = wiggle(1,40);
    [0,0]+w-position;


    Ya une erreur de raisonnement chez moi ?

    RépondreSupprimer
  3. Bonjour Chatton,

    il s'agissait tout simplement d'un oubli de ma part en écrivant l'article, d'ailleurs le "-position" était bien présent à la ligne un peu au dessus, je l'ai juste oublié à la fin. L'erreur est corrigée, merci de l'avoir remarquée.

    RépondreSupprimer
  4. Pour la position de ton Null, tu te compliques drolement la vie :
    Le [0,0] ne sert à rien, c'est comme écrire x+0 à la place de x.
    Il te suffit d'écrire "wiggle(1,40)", puisque la position est comprise dans le wiggle, la position reste donc animable avec des clefs.

    RépondreSupprimer
  5. Bonjour,

    Voilà, je me bats avec cette histoire de mouches depuis le début de la soirée, je possède cs5 en anglais, j'ai remplacé Curseur par Slider.. et AE me dit qu'il y a une erreur

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

    Si tu as une idée de la raison, merci à toi..

    RépondreSupprimer
  6. Bonsoir,

    Je viens de voir ta réponse,
    AE dit ceci" expression result must be of dimension 2, not 1
    Expression disabled.
    Peut-être et sans doute une erreur de ma part, merci de ton indulgence et ta compréhension si tel est le cas.
    Je me suis mis récemment aux expressions afin de gagner du temps dans mon travail et par intérêt.

    Merci

    Bien à toi.

    Thomas

    RépondreSupprimer
  7. Ok, donc cette expression a du être appliqué à la position ou l'échelle, qui demande 2 valeurs (x et y).

    Si ton expression se termine ainsi, AE utilise la dernière variable créée comme valeur finale, en l'occurence :

    amax=thisComp.layer("Nul 1").effect("amp max")("Slider");

    Il te manque donc la suite de l'expression, car là AE te dit que la valeur pour cette propriété doit être de dimension 2, et donc de la forme [x,y].

    Là pour le moment du a juste défini les variables qui font référence aux différents slider.

    RépondreSupprimer
  8. Bonjour,
    Une petite question de logique, vous dites :
    "On demande donc que la mouche ait la meme position que la cible, avec un retard dans le temps vallant R."
    "p.valueAtTime(time-R)"

    Ok, ça fonctionne. Mais quelque-chose m'échappe, pourquoi retirer R au temps courant ?
    En réfléchissant je trouverais logique de l'ajouter...
    Merci en tout cas pour les MégaTuto !

    Cordialement,
    Vincent2

    RépondreSupprimer
  9. On demande que la mouche aille chercher la position de la cible à un instant donné. Si on demande que l'instant soit Time, la mouche va avoir la même position que la cible. Donc si la mouche est en retard, c'est qu'elle va chercher une position passée. Si on met time+R, on cherche une position dans le futur, puisque R est positif. Si R=2, time-R est bien inférieur à time. C'est bien cela que l'on veut.

    RépondreSupprimer
  10. Actuellement, j'ai un calque CIBLE et une dizaine de calques qui s'appellent "SUIVEUR01", "SUIVEUR02", "SUIVEUR03", ...
    Je souhaiterais connaitre la distance la plus petite entre la cible et un suiveur.
    Je vais donc créer une variable pour chaque distance entre chaque SUIVEUR et CIBLE avec la syntaxe suivante : length (pos SUIVEUR[XX], pos CIBLE) et les comparer ensuite avec Math.min
    Mais si demain, je rajoute 8 calques "SUIVEUR" supplémentaires, comment je peux automatiser ça sans créer d'autres variables et devoir les ajouter ensuite à ma fonction Math.min

    N'y a t-il pas une fonction capable de rechercher des calques par leurs noms (tous les "SUIVEUR"), d'ensuite en extraire leur position et la distance avec le calque "CIBLE" pour enfin les comparer et ressortir la plus petite d'entre-elles ?

    RépondreSupprimer