Lassen Sie uns eine 3D-Animation nur mit Python erstellen, ohne Blender zu verwenden! [FBX SDK Python]

20191201_moving_circle_cube.gif

Dies ist der 7. Tagesartikel von Python Adventskalender 2019. Gestern war @ ko-he-8 Einführung von Optionen für die Python-Unit-Test-Bibliothek Nose-19-Typen-.

Ich möchte eine 3D-Animation nur mit Python-Code erstellen

Mit 3D-Animationssoftware wie Blender können Sie 3D-Animationsdateien mit einer praktischen Benutzeroberfläche erstellen!

damit! Wenn Sie ein Schöpfer / Animator sind, verwenden Sie Blender! !! (Nun, Maya ist gut? Dann geh zu Maya)

Jedoch! Ich denke, die meisten Leser von Qiita sind ** Programmierer **!

** Wenn Sie ein Programmierer sind, möchten Sie 3D-Animationen durch Programmieren erstellen! ** ** **

Nein, es sollte durch Programmieren gemacht werden!

Für Sie gibt es ** FBX SDK Python **!

Wenn du das hast! ** Sie können eine 3D-Animationsdatei FBX mit Ihrem Lieblings-Python erstellen! ** ** **

e? Magst du Python nicht? Kann Unity FBX mit C # erstellen?

・ ・ ・

** Jetzt fangen wir an! ** ** **

Diesmal das Ziel

Das Ziel dieser Zeit ist es, eine Animation zu erstellen, die den Würfel wie unten gezeigt in einem Kreis bewegt!

20191201_moving_circle_cube.gif

Vorbereitung: Installieren Sie das FBX SDK Python

Lassen Sie uns zuerst das FBX SDK Python installieren!

Ich habe bereits einige Artikel geschrieben, bereiten Sie sich also bitte entsprechend Ihrer Umgebung vor.

Lassen Sie uns den Beispielcode vorerst verschieben

Lassen Sie uns zuerst den Beispielcode verschieben!

Ich habe den folgenden Beispielcode eingegeben, bitte laden Sie ihn herunter.

GitHub / segurvita / fbx_sdk_python_sample

Drücken Sie nach dem Herunterladen den folgenden Befehl!

python generate_fbx/circle_anim.py resources/cube_ascii.fbx resources/moving_circle_cube_ascii.fbx

Sie sollten eine Datei mit dem Namen "move_circle_cube_ascii.fbx" im Ordner "resources" erstellt haben.

Dies ist das Ergebnis dieser Zeit!

Wenn Sie es mit der Software Autodesk FBX Review öffnen, können Sie sehen, wie sich der Cube wie im vorherigen Video in einem Kreis bewegt. Ich werde! Bitte versuche!

Befehlserklärung

Nun, ich habe Python noch gar nicht erklärt.

Zunächst werde ich anhand des folgenden Befehls erklären.

python generate_fbx/circle_anim.py resources/cube_ascii.fbx resources/moving_circle_cube_ascii.fbx

generate_fbx / circle_anim.py ist der diesmal verwendete Python-Quellcode. Dann gibt es zwei Argumente. Das ist jeder

Es ist geworden.

Python-Kommentar

Schauen wir uns als nächstes generate_fbx / circle_anim.py an!

Das ganze Bild sieht so aus!

circle_anim.py


import sys
import math
from fbx import *

fps = 30.0
rps = 0.5

def generate_anim_stack(scene):
    #Funktion
def generate_anim_layer(scene, anim_stack, node):
    #Funktion
def prot_circle(degree, time, curve_t_x, curve_t_y, curve_r_z):
    #Funktion
def move_circle(node, anim_base_layer):
    #Funktion
def get_ascii_format_id(manager):
    #Funktion
def main(obj_path, fbx_path):
    #Funktion

if __name__ == '__main__':
    # get argument
    args = sys.argv

    if len(args) < 2:
        print('Arguments are too short')
    else:
        main(args[1], args[2])

Es gibt viele Funktionen, daher werde ich dieses Mal nur den Teil erklären, der sich auf 3D-Animation bezieht.

Schauen Sie sich die Hauptfunktion an

Erstens ist die Hauptfunktion. Der Teil, der sich auf Animation bezieht, ist wie folgt.

def main(obj_path, fbx_path):
    #Erstellen Sie verschiedene Instanzen
    manager = FbxManager.Create()
    scene = FbxScene.Create(manager, "fbxScene")
    importer = FbxImporter.Create(manager, "")
    exporter = FbxExporter.Create(manager, "")

    #Importieren Sie die Datei in die Szene
    importer.Initialize(obj_path, -1)
    importer.Import(scene)

    #Erstellen Sie einen Animationsstapel in der Szene
    anim_stack = generate_anim_stack(scene)

    #Holen Sie sich den Wurzelknoten (den höchsten Knoten in der Szene)
    root_node = scene.GetRootNode()
    
    #Wenn es einen Wurzelknoten gibt
    if (root_node):
        #Schleife um die Anzahl der untergeordneten Knoten direkt unter der Wurzel
        for i in range(root_node.GetChildCount()):
            #Holen Sie sich einen untergeordneten Knoten
            node = root_node.GetChild(i)

            #Erstellen Sie eine Animationsebene
            anim_base_layer = generate_anim_layer(scene, anim_stack, node)

            #Erstellen Sie eine Animationskurve
            move_circle(node, anim_base_layer)

    #Schreiben Sie die Szene in eine Datei
    exporter.Initialize(fbx_path, get_ascii_format_id(manager))
    exporter.Export(scene)

    #Zerstören Sie die Instanz
    exporter.Destroy()
    importer.Destroy()
    scene.Destroy()
    manager.Destroy()

Es gibt einige unbekannte Begriffe.

Szene: Szene

Eine Szene ist wie der riesige Speicherplatz, den eine FBX-Datei hat.

In dieser Szene werden verschiedene Daten wie Animationen und Netze gespeichert.

(Blender und Unity haben auch das Konzept von Szenen, aber Sie können fast die gleichen Bilder wie diese verwenden!)

Sie können es mit diesem Code generieren.

#Eine Szene machen
scene = FbxScene.Create(manager, "fbxScene")

Knoten: Knoten

Es gibt verschiedene Daten in der Szene. Jeder ist ein Knoten.

Knoten haben eine Eltern-Kind-Beziehung.

Versuchen Sie zum Beispiel alle, Ihre Schultern zu drehen.

Wenn Sie Ihre Schultern drehen, ändert sich die Position Ihrer Ellbogen, richtig?

Mit anderen Worten, der ** Ellbogenknoten ist ein Kind des Schulterknotens **. Untergeordnete Knoten sind vom übergeordneten Knoten betroffen.

Im Gegenteil, wenn Sie nur den Ellbogen drehen, ändert sich die Position der Schulter nicht, oder?

Der übergeordnete Knoten ist vom untergeordneten Knoten nicht betroffen.

Im Fall von FBX sind Gelenke wie Ellbogen und Schultern ebenfalls Knoten, und Animationen und Netze sind alle Knoten.

Wurzelknoten: Wurzelknoten

Der Stammknoten ist das endgültige Ziel, wenn Sie den Eltern eines solchen Knotens folgen.

Es ist der oberste Knoten in der Szene!

Sie können es mit diesem Code erhalten.

#Holen Sie sich den Wurzelknoten (den höchsten Knoten in der Szene)
root_node = scene.GetRootNode()

Sie können die untergeordneten Knoten in der richtigen Reihenfolge erhalten, indem Sie wie folgt schreiben.

#Schleife um die Anzahl der untergeordneten Knoten direkt unter der Wurzel
for i in range(root_node.GetChildCount()):
    #Holen Sie sich einen untergeordneten Knoten
    node = root_node.GetChild(i)

Erstellen Sie einen Animationsstapel

Es wird immer schwieriger ...

Ein Animationsstapel ist ein Knoten, der Daten organisiert, die sich auf die Animation beziehen.

Sie können nicht ohne es animieren!

Lassen Sie uns vorerst eine machen.

Im Beispielcode wird es von einer Funktion namens "generate_anim_stack" erstellt.

def generate_anim_stack(scene):
    #Erstellen Sie einen Animationsstapel
    anim_stack = FbxAnimStack.Create(scene, "stack")

    return anim_stack

Du kannst es damit schaffen!

Lassen Sie uns eine Animationsebene erstellen

Ein weiterer mysteriöser Begriff ... werde ich erklären.

Es gibt verschiedene Bewegungen in der 3D-Animation, oder?

Laufen / Gehen / Springen ...

Jede dieser Bewegungen wird in der FBX-Terminologie als ** Animationsebene ** bezeichnet. (Es tut mir leid, wenn ich einen Fehler gemacht habe)

Dieses Mal machen wir nur eine kreisförmige Bewegung, also machen wir vorerst eine!

def generate_anim_layer(scene, anim_stack, node):
    #Holen Sie sich den Namen des Knotens (Würfels)
    node_name = node.GetName()

    #Setzen Sie die Position und Drehung des Knotens (Würfels) auf 0
    node.LclTranslation.Set(FbxDouble3(0.0, 0.0, 0.0))
    node.LclRotation.Set(FbxDouble3(0.0, 0.0, 0.0))

    #Erstellen Sie eine Animationsebene (benennen Sie die Knoten, damit sie unterschieden werden können).
    anim_base_layer = FbxAnimLayer.Create(scene, "layer_" + node_name)
    
    #Fügen Sie eine Animationsebene unter dem Animationsstapel hinzu
    anim_stack.AddMember(anim_base_layer)

    #Erstellen Sie einen Animationskurvenknoten
    anim_curve_node = node.LclTranslation.GetCurveNode(
        anim_base_layer, True
    )
    
    #Gibt die Animationsebene zurück
    return anim_base_layer

Jetzt können Sie eine Animationsebene erstellen!

・ ・ ・

Irgendwie tauchte unterwegs der mysteriöse Begriff Animationskurvenknoten auf ...

Dies sind die Daten, die zum Animieren der Informationen über die Position und Drehung eines Knotens (in diesem Fall eines Würfels) benötigt werden. Ich brauche es vorerst, also lass es uns machen. (Ich verstehe es auch nicht wirklich. Es tut mir leid.)

Lassen Sie uns eine Animationskurve erstellen

Ahh! Ein weiterer mysteriöser Begriff!

Um die Wahrheit zu sagen, wenn Sie einen Knoten (Würfel) animieren,

Es gibt verschiedene Animationen, oder?

Wenn Sie beispielsweise eine kreisförmige Bewegung wie diese ausführen möchten,

Sie werden drei Koordinaten wie folgt verschieben.

Jedes davon ist eine ** Animationskurve **!

(Das Konzept entspricht fast der Animationskurve von Blender und Unity.)

Diesmal gibt es drei Animationskurven!

Hier ist also der Beispielcode.

def move_circle(node, anim_base_layer):
    #Erstellen Sie eine Animationskurve der x-Koordinate der Knotenposition
    curve_t_x = node.LclTranslation.GetCurve(
        anim_base_layer, "X", True
    )
    
    #Erstellen Sie eine Animationskurve der y-Koordinate der Knotenposition
    curve_t_y = node.LclTranslation.GetCurve(
        anim_base_layer, "Y", True
    )
    
    #Erstellen Sie eine Animationskurve der z-Koordinate in Drehrichtung des Knotens
    curve_r_z = node.LclRotation.GetCurve(
        anim_base_layer, "Z", True
    )

    #Bereiten Sie Variablen für die Zeiterfassung vor
    time = FbxTime()

    #Starten Sie die Aufnahme der Animationskurve
    curve_t_x.KeyModifyBegin()
    curve_t_y.KeyModifyBegin()
    curve_r_z.KeyModifyBegin()

    # fps =30 (30 Bilder in 1 Sekunde)
    # rps = 0.5 (Ein halber Kreis in 1 Sekunde)
    # fps/rps =60 (1 Runde kreisförmige Bewegung in 60 Bildern)
    #Verarbeiten Sie 60 Frames Frame für Frame.
    for frame in range(int(fps / rps)):
        #Berechnen Sie die verstrichene Zeit. Anzahl der Frames/fps
        sec = float(frame) / fps
        
        #Verstrichene Zeit aufzeichnen
        time.SetSecondDouble(sec)
        
        #Berechnen Sie den Drehwinkel. rps x verstrichene Zeit x 360 °
        degree = rps * sec * 360.0
        
        #Zeichnen Sie den Wert entsprechend dem Drehwinkel auf der Animationskurve
        prot_circle(degree, time, curve_t_x, curve_t_y, curve_r_z)

    #Beenden Sie die Aufnahme der Animationskurve
    curve_t_x.KeyModifyEnd()
    curve_t_y.KeyModifyEnd()
    curve_r_z.KeyModifyEnd()

Es gibt verschiedene detaillierte Berechnungsformeln, aber Sie können sehen, dass die verstrichene Zeit für jeden Frame aufgezeichnet und der Drehwinkel der Kreisbewegung berechnet wird.

Der Ort, an dem der Wert in der Animationskurve tatsächlich aufgezeichnet wird, ist in der Funktion "prot_circle" beschrieben.

Fügen Sie der Animationskurve einen Schlüssel hinzu

Das Aufzeichnen von Werten auf einer Animationskurve entspricht dem Hinzufügen eines Schlüssels.

Unten finden Sie den Code für den Schlüsseladditionsprozess.

def prot_circle(degree, time, curve_t_x, curve_t_y, curve_r_z):
    #Drehwinkel in Bogenmaß umrechnen
    radian = math.radians(degree)

    #Die x-Koordinate der Position ist cos(radian)Berechnen Sie mit und fügen Sie den Schlüssel hinzu
    key_index, key_last = curve_t_x.KeyAdd(time)
    curve_t_x.KeySet(
        key_index, time, math.cos(radian), FbxAnimCurveDef.eInterpolationLinear
    )

    #Die y-Koordinate der Position ist sin(radian)Berechnen Sie mit und fügen Sie den Schlüssel hinzu
    key_index, key_last = curve_t_y.KeyAdd(time)
    curve_t_y.KeySet(
        key_index, time, math.sin(radian), FbxAnimCurveDef.eInterpolationLinear
    )

    #Fügen Sie einen Schlüssel hinzu, während Sie die z-Koordinate in Drehrichtung als Frequenz anstelle eines Bogenmaßes beibehalten
    key_index, key_last = curve_r_z.KeyAdd(time)
    curve_r_z.KeySet(
        key_index, time, degree, FbxAnimCurveDef.eInterpolationLinear
    )

Wenn Sie diese Funktion Frame für Frame aufrufen, werden die Tasten Frame für Frame zu den drei Animationskurven hinzugefügt.

Hier wird der Schlüssel hinzugefügt.

key_index, key_last = curve_t_x.KeyAdd(time)

Dadurch wird der Schlüssel hinzugefügt.

Für diejenigen, die mit Python nicht vertraut sind, gibt es für alle Fälle zwei Rückgabewerte für die Funktion "KeyAdd", bei der es sich um den Code handelt, der "key_index" bzw. "key_last" zugewiesen ist.

Das Schreiben von zwei Variablen nebeneinander auf diese Weise wird manchmal als Taple gelesen.

Dieses Mal wird die Schlüsselnummer key_index zugewiesen. Ich benutze key_last nicht, also ignoriere es.

Der folgende Code legt den tatsächlichen Wert für diesen key_index fest.

curve_t_x.KeySet(
    key_index, time, math.cos(radian), FbxAnimCurveDef.eInterpolationLinear
)

Damit ist die Erklärung von Python abgeschlossen! Danke für Ihre Unterstützung!

schließlich

Danke fürs Lesen.

Jetzt können Sie 3D-Animationen mit nur Python erstellen, ohne Blender zu verwenden! !!

Bei der Erstellung dieses Artikels habe ich auf die folgenden Seiten verwiesen.

Recommended Posts

Lassen Sie uns eine 3D-Animation nur mit Python erstellen, ohne Blender zu verwenden! [FBX SDK Python]
Lassen Sie uns eine GUI mit Python erstellen.
Lassen Sie uns einen Web-Chat mit WebSocket mit AWS serverless (Python) durchführen!
Lassen Sie uns mit Python ein Shiritori-Spiel machen
Arbeiten mit OpenStack mit dem Python SDK
Lassen Sie uns mit Python langsam sprechen
Erstellen Sie ein Webframework mit Python! (1)
Machen wir einen Twitter-Bot mit Python!
Erstellen Sie ein Webframework mit Python! (2)
[Blender x Python] Beginnen wir mit Blender Python !!
Lassen Sie uns mit SWIG ein Modul für Python erstellen
[Lass uns mit Python spielen] Ein Haushaltsbuch erstellen
Versuchen Sie, ein einfaches Spiel mit Python 3 und iPhone zu erstellen
Lassen Sie Python in einer Zeile segfo, ohne ctypes zu verwenden
[Super einfach] Machen wir einen LINE BOT mit Python.
Führen Sie Blender mit Python aus
Lassen Sie uns mit Python einen Web-Socket-Client erstellen. (Zugriffstoken-Authentifizierung)
[Blender Python] Zeigen Sie Bilder in 3D-Ansicht mit OpenGL (bgl) an.
So verschieben Sie ein zweidimensionales Array nur mit Python [Hinweis]
Spielen wir mit der 4. Dimension der 4. Dimension
[S3] CRUD mit S3 unter Verwendung von Python [Python]
Verwenden von Quaternion mit Python ~ numpy-quaternion ~
Erstellen Sie ein 3D-GIF mit Python3
[Python] Verwenden von OpenCV mit Python (Basic)
Machen wir Othello mit wxPython
Machen Sie eine Lotterie mit Python
Schreiben wir Python mitinema4d.
Verwenden von OpenCV mit Python @Mac
Senden Sie mit Python mit Google Mail
Ich habe versucht, eine ToDo-App mit einer Flasche mit Python zu erstellen