Automate Blender Animation with Python and CSV Data

Automate Blender Animation with Python and CSV Data

La création manuelle de keyframes fonctionne très bien pour quelques plans, mais devient rapidement répétitive lorsque vous devez réaliser les mêmes animations. Le temps que vous passez à faire glisser des poignées dans l’éditeur de courbes, c’est du temps que vous pourriez consacrer à quelque chose de plus intéressant.

Le scripting Python dans Blender résout un problème précis : toute animation répétitive, pilotée par des données, ou qui doit être reproduite de manière fiable sur plusieurs objets ou plusieurs plans, ne devrait pas être créée à la main. Ce tutoriel vous montrera exactement comment faire.

À la fin de cet article, vous disposerez d’un script fonctionnel qui lit les données de position de caméra depuis un fichier CSV et produit une animation complète dans Blender sans aucune keyframe manuelle. Vous pouvez déposer ce script dans n’importe quel pipeline de production, remplacer le CSV, et obtenir une nouvelle animation en quelques secondes.

1. Structures de données d’animation

Avant d’écrire du code, vous devez comprendre les structures de données que Blender utilise en interne.

La hiérarchie fonctionne comme suit : un Objet (2D ou 3D) contient des données d’animation, ces données d’animation référencent une Action, l’Action contient une collection de courbes F-Curves, et chaque F-Curve contient une séquence de points de keyframe.

Chaque F-Curve correspond exactement à un seul canal. Le canal est identifié par deux éléments : un data_path (une chaîne de caractères comme "location" ou "rotation_euler") et un array_index (un entier qui indique quel axe : 0 pour X, 1 pour Y, et 2 pour Z). Chaque point de keyframe sur cette F-Curve est une paire de coordonnées : un numéro de frame et une valeur.

Les objets Python utiles à connaître sont bpy.data.actions, action.fcurves, fcurve.keyframe_points, ainsi que les attributs data_path et array_index sur chaque F-Curve.

Un point pratique pour les studios : il est toujours une bonne idée de nommer explicitement vos Actions. Blender crée des Actions anonymes par défaut, et elles disparaissent quand un objet est dupliqué ou que le fichier est nettoyé. Les nommer vous donne quelque chose de stable à référencer dans les scripts, et quelque chose d’identifiable dans l’éditeur d’Action lorsqu’un problème doit être retrouvé plus tard.

2. Insérer des keyframes par programme

Il existe deux méthodes pour insérer des keyframes via Python, et choisir la bonne a un impact sur les performances.

La première méthode est object.keyframe_insert(data_path, index, frame). Elle reproduit ce qui se passe lorsque vous appuyez sur I dans la vue. Elle respecte les drivers et les contraintes, évalue correctement la scène, et constitue l’option la plus sûre lorsque vous travaillez avec un petit nombre de keyframes, ou lorsque votre objet dépend d’autres éléments de la scène.

import bpy

obj = bpy.data.objects["Cube"]

for frame in range(0, 60, 5):
    obj.location.x = frame * 0.1
    obj.keyframe_insert(data_path="location", index=0, frame=frame)

L’argument index=0 indique à Blender de keyframer uniquement l’axe X. Utilisez 1 pour Y et 2 pour Z. Si vous omettez l’index, les trois axes sont keyframés, ce qui n’est souvent pas ce que vous voulez.

Une erreur fréquente avec cette méthode consiste à oublier de définir la valeur avant d’appeler keyframe_insert. La fonction enregistre la valeur actuelle de la propriété. Si vous l’appelez sans mettre à jour la valeur au préalable, toutes les keyframes auront la même valeur et votre animation sera plate.

La deuxième méthode insère directement des points dans une F-Curve :

fcurve.keyframe_points.insert(frame, value)

Cette méthode évite entièrement la couche de logique de l’interface utilisateur, ce qui la rend significativement plus rapide pour insérer des centaines ou des milliers de keyframes. Utilisez-la lorsque vous générez des animations pilotées par des données à partir de sources externes et que la vitesse est un critère. L’inconvénient est qu’elle ne déclenche pas l’évaluation des contraintes ou des drivers ; utilisez donc keyframe_insert si votre objet a des dépendances qui doivent être mises à jour.

3. Lire et modifier les F-Curves

Une fois les keyframes créées, vous pouvez accéder et modifier directement les F-Curves sous-jacentes pour contrôler précisément l’interpolation et le timing.

Pour accéder à une F-Curve après l’insertion des keyframes :

action = obj.animation_data.action
fcurve = action.fcurves.find("location", index=0)

# OR

slot = action.slots[0]
channelbag = action.layers[0].strips[0].channelbag(slot)

for fcurve in channelbag.fcurves:
    # ... iterate over every fcurve
  • Une Action est un conteneur de niveau supérieur qui regroupe toutes les données d’animation.
  • Un Slot associe l’Action à un objet spécifique, permettant à une seule action d’animer plusieurs objets.
  • Une Layer est une couche d’animation qui peut être mixée avec d’autres, comme des pistes dans un éditeur vidéo.
  • Un Strip est un clip sur une plage de temps à l’intérieur d’une layer, similaire à un clip sur une timeline.
  • Un Channelbag regroupe toutes les F-Curves appartenant à un slot spécifique dans un strip.
  • Une F-curve anime un canal de propriété unique (par ex. la position X) dans le temps via des keyframes.
  • Un Keyframe point est une keyframe unique sur une F-Curve, avec un mode d’interpolation qui contrôle le mouvement jusqu’à la key suivante.

Pour lire ou modifier les valeurs des keyframes :

for kp in fcurve.keyframe_points:
    print(kp.co)
    kp.co.y *= 2

fcurve.update()

Nous parcourons tous les points de keyframe dans une F-Curve Blender, affichons chaque keyframe avec sa paire de coordonnées (frame, valeur), doublons la composante valeur, puis mettons à jour la courbe pour appliquer les changements.

L’appel à fcurve.update() n’est pas optionnel. Blender met en cache les données de courbe en interne, et le fait de sauter cet appel signifie que vos modifications peuvent ne pas prendre effet, ou produire des résultats incohérents pendant le rendu.

Pour l’interpolation, les trois modes que vous utiliserez le plus souvent en production sont CONSTANT, LINEAR et BEZIER. CONSTANT conserve la valeur jusqu’à la keyframe suivante, ce qui est utile pour l’animation de type cut-out et pour tout ce qui repose sur des états discrets. LINEAR produit un mouvement mécanique et régulier, qui fonctionne bien pour les rigs caméra, les animations d’interface utilisateur et les effets procéduraux. BEZIER produit un mouvement organique avec accélération/décélération, et c’est le mode par défaut pour la plupart des travaux d’animation.

Pour définir l’interpolation sur tous les points de keyframe d’une courbe :

for kp in fcurve.keyframe_points:
    kp.interpolation = "LINEAR"

fcurve.update()

4. Construire une animation pilotée par des données depuis un CSV

Maintenant que vous connaissez les bases, passons à un exemple plus complet que vous pourriez même utiliser en production. Le scénario est un survol caméra, où les données de position ont été exportées depuis un autre outil : une application de levés, un moteur de jeu, un outil de previs, ou encore une feuille de calcul créée par un réalisateur ou un client.

Le format CSV de ce tutoriel est simple : une ligne d’en-tête, suivie de lignes de données avec quatre colonnes, frame, x, y et z.

frame,x,y,z
0,0.0,0.0,5.0
10,1.5,0.2,4.8
20,3.1,0.5,4.5
30,4.8,0.9,4.1

Voici maintenant le script complet pour animer une caméra le long d’un chemin défini dans le fichier CSV :

import bpy
import csv

obj = bpy.data.objects["Camera"]
scene = bpy.context.scene

obj.animation_data_clear()

with open("camera_path.csv", newline="") as f:
    reader = csv.reader(f)
    next(reader)
    for row in reader:
        frame = int(row[0])
        x, y, z = float(row[1]), float(row[2]), float(row[3])
        scene.frame_set(frame)
        obj.location = (x, y, z)
        obj.keyframe_insert(data_path="location", frame=frame)

action = obj.animation_data.action
action.name = "CAM_flythrough_v01"

slot = action.slots[0]
channelbag = action.layers[0].strips[0].channelbag(slot)

for fcurve in channelbag.fcurves:
    for kp in fcurve.keyframe_points:
        kp.interpolation = "LINEAR"
    fcurve.update()

print("Done. Keyframes inserted and interpolation set.")
  • D’abord, on récupère l’objet Camera et la scène actuelle, puis on efface toutes les données d’animation qui y existaient.
  • Ensuite, on ouvre le fichier camera_path.csv, on lit chaque ligne (numéro de frame + positions X/Y/Z), on saute à la frame correspondante avec frame_set, on définit la position de la caméra, puis on insère une keyframe de localisation.
  • On récupère l’Action d’animation qui vient d’être créée et on lui donne le nom « CAM_flythrough_v01 ».
  • Pour définir l’interpolation en linéaire, on navigue dans la structure des données d’animation (slots → layers → strips → channelbag) pour atteindre chaque F-curve, puis on définit l’interpolation de toutes les keyframes sur LINEAR afin que la caméra se déplace à une vitesse constante entre les points. Dans cet exemple simple, nous n’avons qu’un seul slot/layer/strip/channelbag, donc c’est plus facile ; autrement, il faudrait itérer de manière récursive.
  • Enfin, on appelle fcurve.update() sur chaque courbe et on affiche un dernier message de confirmation.

Essayez le script vous-même : il est disponible sur Github dans notre dépôt pour les tutoriels de blog.

Conclusion

Nous avons désormais une étape de pipeline reproductible qui remplace le keyframing manuel pour toute animation dont les valeurs peuvent être exprimées comme des données tabulaires.

Le même schéma s’applique à la visibilité des objets, aux propriétés des matériaux, à l’intensité des lumières, à la longueur focale de la caméra, ou à n’importe quelle autre propriété que l’on peut keyframer dans Blender : toute source de données capable de produire un CSV, un fichier JSON ou une sortie structurée peut alimenter directement une animation Blender, sans qu’un animateur touche la timeline.

Et ce schéma a une vraie valeur pour un studio : les données externes entrent, Python les transforme en keyframes avec une interpolation cohérente, et le résultat est déterministe et contrôlable par version. Quand vous devez changer le chemin de la caméra, il vous suffit de régénérer la scène. Quand le timing doit évoluer sur 40 plans, vous mettez à jour le script. Vous ne faites plus ce travail à la main.