Aide pour After Effect, techniques, expressions.

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.

18 commentaires:

  1. Bonjour, je suis avec attention chaque étape, votre explication est trés simple, merci de prendre le temps de nous faire partager vos connaissances.
    J'aurais souhaité savoir comment vous nommiez "coeff" l'effet âramétre glissiere...
    Merci

    RépondreSupprimer
  2. Ha tiens, un commentaire qui est passé entre les gouttes...
    Pour renommer calque, effet, masque ou autre, il suffit de sélectionner l'intéressé, de taper sur la touche Entrée, et de modifier le nom

    RépondreSupprimer
  3. Bonjour,
    j'ai une expression qui me permet de retrouver la position d'un calque dans une précomposition.
    Dans la position, j'ai écrit:
    cible= comp("ma precomp").layer("mon calque");
    cible.toComp(cible.anchorPoint)

    ça marche tres bien, mais je veux maintenant lui rajouter un valueAtTime.
    Comment faire ?
    j'ai essayé plein de truc, mais ca ne marche pas, je m'embrouille a cause du toComp.
    Peux tu m'aider?

    merci beaucoup
    ton site est génial

    RépondreSupprimer
  4. Alors alors....
    C'est vrai, parfois valueAtTime peut être capricieux, car je suppose que tu as écrit quelque chose qui ressemble à ça :

    cible= comp("ma precomp").layer("mon calque");
    A=cible.toComp(cible.anchorPoint);
    A.valueAtTime(time-decalage)

    Et After Effect n'en a pas voulu. Voilà pourquoi:
    La fonction valueAtTime va chercher la valeur d'une variable à un instant donné. Mais elle ne peut trouver une valeur d'une variable d'une propriété, et non une de tes créations.
    Tu dois donc écrire ceci :

    cible= comp("ma precomp").layer("mon calque");
    cible.toComp(cible.anchorPoint.valueAtTime(time-décalage))

    Ainsi, le valueAtTime va directement chercher la valeur chez le anchorPoint.

    J'espère avoir été clair.

    RépondreSupprimer
  5. je vois t'as réponse que maintenant mais merci d'avoir été si rapide.
    C'est effectivement ce que j'avais écrit, l'expression est donc ok mais ça ne fait pas ce que je veux.
    j'ai donc ecrit sur la position de mon layer(3):

    cible= comp("ma precomp").layer("mon calque");
    t= thisComp.layer("ma precomp").timeRemap;
    cible.toComp(cible.anchorPoint.valueAtTime(t))

    Ma precomp a un timeremap avec des clef de maintien, je devrais donc voir mon calque (3) se deplacer en cut et bien non, il bouge exactement comme mon calque cible.
    Ce genre de traking fonctionne parfaitement mais il reste toujours en synchro.
    C'est curieux.
    Mon calque cible est animé en position, il est parenté, son point d'ancrage est fixe.
    je ne comprend pas, c'est domage.
    Je suis pris par le temps, je vais l'animer a la main en esperant ne pas avoir de retake!

    merci beaucoup de ta générosité
    Si tu as une idée, je suis preuneur.

    merci encore

    RépondreSupprimer
  6. Je ne suis pas sur qu'il soit une bonne idée d'utiliser un remappage temporel pour charger des clefs venant un timing différent.
    Je te redirige donc vers ces 2 articles :

    http://lefreelancesaucisse.blogspot.com/2010/01/remappage-temporel-de-clef.html

    et

    http://lefreelancesaucisse.blogspot.com/2010/01/remappage-temporel-de-clef-2.html

    qui sont une façon d'avoir un time remapping sur les clefs

    RépondreSupprimer
  7. Salut ! Je suis à la recherche de quelqu'un qui voudrait bien m'aider, et c'est pas évident à trouver ... Je cherche à savoir comment définir une position aléatoire pour un solide, puis appliquer cette même position aléatoire +1 à ce même solide quelques images plus loin pour les x et les y. J'ai pigé random et seedRandom mais je n'y arrive pas. Merci d'avance pour ta réponse !

    RépondreSupprimer
  8. Ouille ! Si vite ? :o) Eh bien je voudrais mettre le solide à un endroit aléatoire et qu'il n'en bouge pas jusqu'à l'instant T. Ca j,y arrive. Et puis à l'instant T, je voudrais qu'il prenne sa position actuelle +1. Je me demandais si on ne pouvais pas affecter des expressions à des clefs, j'aurais pu y arriver comme ça je crois.

    RépondreSupprimer
  9. Oui, c'est exactement ça ! :o)

    RépondreSupprimer
  10. En fait, ça parait peu mais c'est ce qui fait toute la différence pour la vidéo que je réalise.

    RépondreSupprimer
  11. imaginons que "P" soit ta valeur hasard sur [x,y], et que tu aies un marqueur temps à ton moment T, ça donne en gros :

    P=ta position random;
    if (time>=thisComp.marker.key("T").time)
    { P=P+[1,1]};

    P

    RépondreSupprimer
  12. OK ! Merci pour ta réponse ! Je m'y met dès que j'ai un peu de temps et je t'en dis plus. :o)

    RépondreSupprimer
  13. Bonjour,

    Je ne sais pas si cette publication est encore active, mais je tente le coup !
    Je souhaiterai utiliser l'expression valueAtTime sur un calque en modifiant la valeur de position Y sur celui-ci.
    J'ai essayé le code ci-dessous, mais ça ne fonctionne pas :

    VarX=thisComp.layer("Position_Languette_Controle").transform.position[0];
    VarY=thisComp.layer("Position_Languette_Controle").transform.position[1]+314;
    PosX=VarX.valueAtTime(time-0.2);
    PosX=VarY.valueAtTime(time-0.2);
    [PosX,PosY];

    Merci pour ton aide !

    RépondreSupprimer
  14. Désolé pour mon précédent post, j'ai trouvé la réponse sur une de tes publications sur les positions en 2007 :

    P=thisComp.layer("Position_Languette_Controle").transform.position.valueAtTime(time-0.5);
    [P[0],Pos[1]+314];

    Merci pour l'aide qu'apporte ton site !

    RépondreSupprimer