Ceci est l'article du 7ème jour du Calendrier de l'Avent Python 2019. Hier, c'était @ ko-he-8 Introduction d'options pour la bibliothèque de tests unitaires python Nose-19 types-.
Avec un logiciel d'animation 3D comme Blender, vous pouvez créer des fichiers d'animation 3D avec une interface graphique pratique!
alors! Si vous êtes un créateur / animateur, utilisez Blender! !! (Eh bien, Maya va bien? Alors allez voir Maya)
Pourtant! Je pense que la plupart des lecteurs de Qiita sont des ** programmeurs **!
** Si vous êtes programmeur, vous souhaitez créer des animations 3D par programmation! ** **
Non, cela doit être fait par programmation!
Pour vous, il y a ** FBX SDK Python **!
Si vous avez ça! ** Vous pouvez générer un fichier d'animation 3D FBX avec votre Python préféré! ** **
e? Vous n'aimez pas Python? Unity peut-il créer FBX avec C #?
・ ・ ・
** Maintenant, commençons! ** **
Le but de cette fois est de créer une animation qui fait bouger le cube en cercle comme indiqué ci-dessous!
Tout d'abord, installons le FBX SDK Python!
J'ai écrit quelques articles avant, alors préparez-vous en fonction de votre propre environnement.
Tout d'abord, déplaçons en fait l'exemple de code!
J'ai mis l'exemple de code ci-dessous, veuillez donc le télécharger.
GitHub / segurvita / fbx_sdk_python_sample
Après le téléchargement, appuyez sur la commande suivante!
python generate_fbx/circle_anim.py resources/cube_ascii.fbx resources/moving_circle_cube_ascii.fbx
Vous devriez avoir créé un fichier appelé moving_circle_cube_ascii.fbx
dans le dossier resources
.
C'est le livrable de cette fois!
Si vous l'ouvrez avec le logiciel Autodesk FBX Review, vous pouvez voir le cube se déplacer dans un cercle comme la vidéo précédente. Je vais! S'il vous plaît essayez!
Eh bien, je n'ai pas encore expliqué Python.
Tout d'abord, je vais expliquer à partir de la commande suivante.
python generate_fbx/circle_anim.py resources/cube_ascii.fbx resources/moving_circle_cube_ascii.fbx
generate_fbx / circle_anim.py
est le code source Python utilisé cette fois. Ensuite, il y a deux arguments. C'est chacun
--Fichier d'entrée: resources / cube_ascii.fbx
--Fichier de sortie: resources / moving_circle_cube_ascii.fbx
Il est devenu.
Ensuite, jetons un œil à generate_fbx / circle_anim.py
!
L'image entière ressemble à ceci!
circle_anim.py
import sys
import math
from fbx import *
fps = 30.0
rps = 0.5
def generate_anim_stack(scene):
#une fonction
def generate_anim_layer(scene, anim_stack, node):
#une fonction
def prot_circle(degree, time, curve_t_x, curve_t_y, curve_r_z):
#une fonction
def move_circle(node, anim_base_layer):
#une fonction
def get_ascii_format_id(manager):
#une fonction
def main(obj_path, fbx_path):
#une fonction
if __name__ == '__main__':
# get argument
args = sys.argv
if len(args) < 2:
print('Arguments are too short')
else:
main(args[1], args[2])
Il y a beaucoup de fonctions, donc cette fois je n'expliquerai que la partie liée à l'animation 3D.
La première est la fonction principale. La partie liée à l'animation est comme ça.
def main(obj_path, fbx_path):
#Créer diverses instances
manager = FbxManager.Create()
scene = FbxScene.Create(manager, "fbxScene")
importer = FbxImporter.Create(manager, "")
exporter = FbxExporter.Create(manager, "")
#Chargez le fichier dans la scène
importer.Initialize(obj_path, -1)
importer.Import(scene)
#Créer une pile d'animation dans la scène
anim_stack = generate_anim_stack(scene)
#Obtenez le nœud racine (le nœud le plus élevé de la scène)
root_node = scene.GetRootNode()
#S'il y a un nœud racine
if (root_node):
#Boucle par le nombre de nœuds enfants directement sous la racine
for i in range(root_node.GetChildCount()):
#Obtenir un nœud enfant
node = root_node.GetChild(i)
#Créer un calque d'animation
anim_base_layer = generate_anim_layer(scene, anim_stack, node)
#Créer une courbe d'animation
move_circle(node, anim_base_layer)
#Ecrire la scène dans un fichier
exporter.Initialize(fbx_path, get_ascii_format_id(manager))
exporter.Export(scene)
#Détruire l'instance
exporter.Destroy()
importer.Destroy()
scene.Destroy()
manager.Destroy()
Il existe des termes inconnus.
Une scène est comme l'énorme espace dont dispose un fichier FBX.
Diverses données telles que des animations et des maillages sont stockées dans cette scène.
(Blender et Unity ont également le concept de scènes, mais vous pouvez utiliser presque les mêmes images que celles-ci!)
Vous pouvez le générer avec ce code.
#Faire une scène
scene = FbxScene.Create(manager, "fbxScene")
Il existe différentes données dans la scène. Chacun est un nœud.
Les nœuds ont une relation parent-enfant.
Par exemple, tout le monde, essayez de tourner les épaules.
Lorsque vous tournez les épaules, la position de vos coudes change, non?
En d'autres termes, le ** nœud du coude est un enfant du nœud de l'épaule **. Les nœuds enfants sont affectés par le nœud parent.
Au contraire, tourner uniquement le coude ne change pas la position de l'épaule, non?
Le nœud parent n'est pas affecté par le nœud enfant.
Dans le cas de FBX, les articulations telles que les coudes et les épaules sont également des nœuds, et les animations et les maillages sont tous des nœuds.
Le nœud racine est la destination finale lorsque vous suivez les parents d'un tel nœud.
C'est le nœud supérieur de la scène!
Vous pouvez l'obtenir avec ce code.
#Obtenez le nœud racine (le nœud le plus élevé de la scène)
root_node = scene.GetRootNode()
Vous pouvez ordonner les nœuds enfants en écrivant comme suit.
#Boucle par le nombre de nœuds enfants directement sous la racine
for i in range(root_node.GetChildCount()):
#Obtenir un nœud enfant
node = root_node.GetChild(i)
Cela devient de plus en plus difficile ...
Une pile d'animation est un nœud qui organise les données liées à l'animation.
Vous ne pouvez pas animer sans lui!
Pour le moment, faisons-en un.
Dans l'exemple de code, il est créé par une fonction appelée generate_anim_stack
.
def generate_anim_stack(scene):
#Créer une pile d'animation
anim_stack = FbxAnimStack.Create(scene, "stack")
return anim_stack
Vous pouvez le faire avec ça!
Un autre terme mystérieux ... Je vais vous expliquer.
Il y a différents mouvements dans l'animation 3D, non?
Courir / marcher / sauter ...
Chacun de ces mouvements est appelé ** couche d'animation ** dans la terminologie FBX. (Je suis désolé si j'ai fait une erreur)
Cette fois, nous allons simplement faire un mouvement circulaire, alors faisons-en un pour le moment!
def generate_anim_layer(scene, anim_stack, node):
#Obtenez le nom du nœud (cube)
node_name = node.GetName()
#Définissez la position et la rotation du nœud (cube) sur 0
node.LclTranslation.Set(FbxDouble3(0.0, 0.0, 0.0))
node.LclRotation.Set(FbxDouble3(0.0, 0.0, 0.0))
#Créez un calque d'animation (nommez les nœuds afin qu'ils puissent être distingués)
anim_base_layer = FbxAnimLayer.Create(scene, "layer_" + node_name)
#Ajouter une couche d'animation sous la pile d'animations
anim_stack.AddMember(anim_base_layer)
#Créer un nœud de courbe d'animation
anim_curve_node = node.LclTranslation.GetCurveNode(
anim_base_layer, True
)
#Renvoyer le calque d'animation
return anim_base_layer
Vous pouvez maintenant créer un calque d'animation!
・ ・ ・
D'une manière ou d'une autre, le mystérieux terme de nœud de courbe d'animation est apparu sur le chemin ...
Il s'agit des données nécessaires pour animer les informations sur la position et la rotation d'un nœud (dans ce cas, un cube). J'en ai besoin pour le moment, alors faisons-le. (Je ne comprends pas vraiment non plus. Je suis désolé.)
Ahh! Un autre terme mystérieux!
Pour dire la vérité, si vous animez un nœud (cube),
Il existe diverses animations, non?
Par exemple, si vous souhaitez effectuer un mouvement circulaire comme cette fois,
--Déplacez la coordonnée x de la position du nœud --Déplacez la coordonnée y de la position du nœud --Déplacez la coordonnée z dans le sens de rotation du nœud
Vous déplacerez trois coordonnées comme ceci.
Chacun de ces éléments est une ** courbe d'animation **!
(Le concept est presque le même que la courbe d'animation de Blender et Unity)
Cette fois, il y a trois courbes d'animation!
Voici donc l'exemple de code.
def move_circle(node, anim_base_layer):
#Créer une courbe d'animation de la coordonnée x de la position du nœud
curve_t_x = node.LclTranslation.GetCurve(
anim_base_layer, "X", True
)
#Créer une courbe d'animation de la coordonnée y de la position du nœud
curve_t_y = node.LclTranslation.GetCurve(
anim_base_layer, "Y", True
)
#Créer une courbe d'animation de la coordonnée z dans le sens de rotation du nœud
curve_r_z = node.LclRotation.GetCurve(
anim_base_layer, "Z", True
)
#Préparer les variables pour l'enregistrement du temps
time = FbxTime()
#Démarrer l'enregistrement de la courbe d'animation
curve_t_x.KeyModifyBegin()
curve_t_y.KeyModifyBegin()
curve_r_z.KeyModifyBegin()
# fps =30 (30 images en 1 seconde)
# rps = 0.5 (demi-cercle en 1 seconde)
# fps/rps =60 (1 tour de mouvement circulaire en 60 images)
#Traitez 60 images image par image.
for frame in range(int(fps / rps)):
#Calculez le temps écoulé. Nombre de cadres/fps
sec = float(frame) / fps
#Enregistrer le temps écoulé
time.SetSecondDouble(sec)
#Calculez l'angle de rotation. rps x temps écoulé x 360 °
degree = rps * sec * 360.0
#Tracez la valeur en fonction de l'angle de rotation sur la courbe d'animation
prot_circle(degree, time, curve_t_x, curve_t_y, curve_r_z)
#Terminer l'enregistrement de la courbe d'animation
curve_t_x.KeyModifyEnd()
curve_t_y.KeyModifyEnd()
curve_r_z.KeyModifyEnd()
Il existe différentes formules de calcul détaillées, mais vous pouvez voir que le temps écoulé est enregistré pour chaque image et que l'angle de rotation du mouvement circulaire est calculé.
L'endroit où enregistrer réellement la valeur dans la courbe d'animation est décrit dans la fonction prot_circle
, voyons-le donc.
Enregistrer des valeurs sur une courbe d'animation revient à ** ajouter une clé **.
Vous trouverez ci-dessous le code du processus d'ajout de clé.
def prot_circle(degree, time, curve_t_x, curve_t_y, curve_r_z):
#Convertir l'angle de rotation en radian
radian = math.radians(degree)
#La coordonnée x de la position est cos(radian)Calculer avec et ajouter la clé
key_index, key_last = curve_t_x.KeyAdd(time)
curve_t_x.KeySet(
key_index, time, math.cos(radian), FbxAnimCurveDef.eInterpolationLinear
)
#La coordonnée y de la position est sin(radian)Calculer avec et ajouter la clé
key_index, key_last = curve_t_y.KeyAdd(time)
curve_t_y.KeySet(
key_index, time, math.sin(radian), FbxAnimCurveDef.eInterpolationLinear
)
#Ajouter une clé tout en conservant la coordonnée z dans le sens de rotation comme une fréquence au lieu d'un radian
key_index, key_last = curve_r_z.KeyAdd(time)
curve_r_z.KeySet(
key_index, time, degree, FbxAnimCurveDef.eInterpolationLinear
)
En appelant cette fonction image par image, des clés seront ajoutées image par image aux trois courbes d'animation.
C'est là que la clé est ajoutée.
key_index, key_last = curve_t_x.KeyAdd(time)
Cela ajoutera la clé.
Pour ceux qui ne connaissent pas Python, juste au cas où, il y a deux valeurs de retour pour la fonction KeyAdd
, qui est le code attribué respectivement à key_index
et key_last
.
Ecrire deux variables côte à côte de cette manière est parfois lu comme un taple.
Cette fois, le numéro de clé est attribué à «key_index». Je n'utilise pas key_last
, alors ignorez-le.
Le code suivant définit la valeur réelle de cet «index_clé».
curve_t_x.KeySet(
key_index, time, math.cos(radian), FbxAnimCurveDef.eInterpolationLinear
)
Cela conclut l'explication de Python! Merci pour votre soutien!
Merci pour la lecture.
Vous pouvez maintenant créer des animations 3D avec seulement Python, sans utiliser Blender! !!
En créant cet article, je me suis référé aux pages suivantes.
Recommended Posts