VSE

Filmstart – Intro

Der Titel und weitere Angaben zum Film sind Inhalte einer kurzgefassten und thematisch bezogenen Einleitung.

In diesem Teil der Anleitung wird eine Buchstabenanimation erstellt, die per Hand erzeugt, recht aufwendig wäre. Mit einem Python-Skript reduziert sich der Aufwand auf die Details, wie Kamera, Beleuchtung, Kerning-Korrekturen oder Einstellungen der Farben.

Handlungsanweisungen

Aufgaben

  1. Erstelle aus einem eigenen Text einzelne Text-Objekte für jeden Buchstaben.

  2. Variiere die im Beispiel demonstrierten Zufalls-Kombinationen

  3. Gib dem Text ein Material.

  4. Rendere die Animation.

Text Animieren

Text kann, wie jedes Objekt in Blender auf die unterschiedlichste Art & Weise animiert werden. Für ganze Worte und Textzeilen ist das kein Problem. Für einzelne Buchstaben ist der Aufwand schon etwas größer, deshalb soll ein Python-Script uns helfen, schneller zum Ziel zu kommen.

Wir stellen hier die Bewegung einzelner Buchstaben zu einer vordefinierten Endposition vor, an der der Text in Ruhe gelesen werden kann. Der Weg der Buchstaben zu Endposition soll von einem »zufälligen« Startpunkt aus erfolgen. Das per Hand zu steuern, wäre etwas aufwendig, deshalb lohn sich die Entwicklung eines Python-Skripts, das uns schneller zum Ziel führt und viel Raum für Varianten und Experimente gibt.

Das Skript enthält vier Funktionen:

  • Aus einem Text werden Einzelbuchstaben erzeugt und provisorisch an der Endposition platziert.

  • Die zweite Funktion speichert die End-Positionen in einem Dictionary.

  • Die dritte Funktion erzeugt per Zufall die Start-Positionen und speichert die Werte ebenfalls in einem Dictionary

  • Die vierte Funktion setzt die Keyframes für Start und Ende einer jeden Buchstaben-Bewegung, damit kann dann die Animation erzeugt werden.

Die Vorbereitungen:

  • die Kamera soll in der Draufsicht von oben nach unten auf die x- und y-Achse gerichtet sein.

    • Dazu wähle die Kamera aus. Aktiviere mit »N« (der Mauszeiger befindet sich im 3D-Fenster) das Eigenschaften-Panel.

    • Setze dort für Location und Rotation alle Werte auf »0«

    • Zum Schluss setze für den Z-Wert der „Location“ eine 7 ein.

    • Wechsle dann in die Kamera-Perspektive (0 auf der Numerischen Tastatur)

Das Startskript:

#!bpy
"""
Name: 'Flying Letters'
Blender: 2.8
Group: 'Animation'
Tooltip: 'Helperscripts to animate letters'
"""
import bpy


def textToSingleLetters(text="Hallo", x_start=0, y_start=0):
    """ A given text line is divided in single letters (objects). """
    pass


def defineEndPosition(d=None):
    """ Register endposition of all text objects. """
    pass


def calcStartPosition(d=None):
    """ Calculate random start position of all text objects. """
    pass


def setkeyframes(d=None):
    """ One line describing the task of this function  """
    pass


if __name__ == '__main__':
    pass

Wir haben nun die vier wichtigsten Funktionen benannt, das Skript vorbereitet und die Dokumentation angepasst. Nun kann die Umsetzung des ersten Arbeitschrittes beginnen.

Textobjekte erzeugen

 1#!bpy
 2"""
 3Name: 'Flying Letters'
 4Blender: 2.8
 5Group: 'Animation'
 6Tooltip: 'Helperscripts to animate letters'
 7"""
 8import bpy
 9
10
11def textToSingleLetters(text="Hallo", x_start=0, y_start=0):
12    """ A given text line is divided in single letters (objects). """
13
14    counter = 1
15    kerning = .1
16    pos_next_x = 0
17    for letter in text:
18        name = "row_%s_%s" % (y_start, counter)
19        myFontCurve = bpy.data.curves.new(type="FONT", name=name)
20        myFontOb = bpy.data.objects.new(name, myFontCurve)
21        myFontOb.location = (x_start + pos_next_x, y_start, 0)
22        myFontOb.data.body = letter
23        bpy.context.collection.objects.link(myFontOb)
24        counter += 1
25        pos_next_x = pos_next_x + myFontOb.dimensions.x + kerning
26
27
28def defineEndPosition(d=None):
29    """ Register endposition of all text objects. """
30    pass
31
32
33def calcStartPosition(d=None):
34    """ Calculate random start position of all text objects. """
35    pass
36
37
38def setkeyframes(d=None):
39    """ One line describing the task of this function  """
40    pass
41
42
43if __name__ == '__main__':
44
45    bpy.ops.object.select_by_type(type='FONT')
46    bpy.ops.object.delete()
47    textToSingleLetters("Python", y_start=-1, x_start=-2)
48    textToSingleLetters("Blender", y_start=0, x_start=-2)
49    textToSingleLetters("Blend4Web", y_start=1, x_start=-2)

Was passiert hier im Einzelnen:

Zeile(n)

Anmerkung

45-46

Alle vorhandenen Font-Objekte werden

gelöscht…

47-59

drei Zeilen werden abgearbeitet…

14-16

Startwerte werden vorbereitet

17

Für jeden Buchstaben in der Zeile, wiederholen wir

18

Ein Name wird konstruiert

19-22

Ein Buchstabe wird als Objekt angelegt

24-25

die Parameter für den nächsten Buchstaben werden berechnet

Sollten die Abstände nicht gefallen, kann manuell nachjustiert werden oder man entwickelt ein Mapping, das für jeden Buchstaben ein eigenes Kerning [#1]_ definiert. In diesem Tutorial verzichten wir auf diese Feinheit…

Koordinaten speichern

 1#!bpy
 2"""
 3Name: 'Flying Letters'
 4Blender: 2.8
 5Group: 'Animation'
 6Tooltip: 'Helperscripts to animate letters'
 7"""
 8import bpy
 9import random
10
11def textToSingleLetters(text="Hallo", x_start=0, y_start=0):
12    """ A given text line is divided in single letters (objects). """
13    counter = 1
14    kerning = .1
15    pos_next_x = 0
16    for letter in text:
17        name = "row_%s_%s" % (y_start, counter)
18        myFontCurve = bpy.data.curves.new(type="FONT", name=name)
19        myFontOb = bpy.data.objects.new(name, myFontCurve)
20        myFontOb.location = (x_start + pos_next_x, y_start, 0)       
21        myFontOb.data.body = letter
22        bpy.context.collection.objects.link(myFontOb)
23        counter += 1
24        pos_next_x = pos_next_x + myFontOb.dimensions.x + kerning
25 
26def defineEndPosition():
27    """ Register endposition of all text objects. 
28
29        This is the Position of each letter after creation.
30    """
31    data = {}
32    all = [item.name for item in bpy.data.objects]
33    for name in all:
34        if name[0:3] == "row":
35            obj = bpy.data.objects[name]
36            data[name] = [(obj.location.x,
37                           obj.location.y,
38                           obj.location.z)]
39    return data
40
41def calcStartPosition(d=None):
42    """ Calculate random start position of all text objects. """
43
44    all = [item.name for item in bpy.data.objects]
45    for name in all:
46        if name[0:3] == "row":                
47            obj = bpy.data.objects[name]
48            randX = round(random.uniform(-4, 4),3)
49            randY = round(random.uniform(10, 30),3)
50            randZ = round(random.uniform(10, 30),3)
51            d[name].append((randX, randY, randZ))
52    return d
53
54def calcStartEndFrames(d=None, startFrame=10, endFrame=190):
55    """ Calculate random startframe for each object. """
56    pass
57
58
59def setkeyframes(d=None):
60    """ One line describing the task of this function  """
61    pass
62
63if __name__ == '__main__':
64    bpy.ops.object.select_by_type(type='FONT')
65    bpy.ops.object.delete()
66    textToSingleLetters("Python", y_start=-1, x_start=-2)
67    textToSingleLetters("Blender", y_start=0, x_start=-2)
68    textToSingleLetters("Blend4Web", y_start=1, x_start=-2)
69
70    d = defineEndPosition()
71    d = calcStartPosition(d)
72    print(d)

Zeile(n)

Anmerkung

27-39

Die eben platzierten Buchstaben-Objekte haben ihre Endposition

und wir lesen die x-, y- und z-Koordinaten aus. Im Dictionary

d gespeichert, geben wir die Werte zurück

41-52

Die Startposition muss nun festgelegt werden. Die Werte lassen

wir durch den Zufall erzeugen. Weil die vielen

Nachkommastelln nicht benötigt werden, wird abschließend noch

gerundet, bevor die Werte auch im Daten-Dictionary gespeichert

werden.

70-71

hier werden die Funktionen aufgerufen…

72

Eine Ausgabe zeigt den aktuellen Inhalt des Dictionary.

Start und Ende der Animation

In welchem Frame (Bild) ein Objekt zu finden ist, wird durch einen Key-Frame festgelegt. Wenn für ein Objekt zwei Key-Frames definiert sind, berechnet Blender für eine Animation die Position zwischen den Key-Frames. Die Start- und Ende-Position wird wiederum durch den Zufall bestimmt. Die Werte sollten im Bereich der gesamtlänge der Animation liegen.

Hier das Komplette Script:

 1#!bpy
 2"""
 3Name: 'Flying Letters'
 4Blender: 2.8
 5Group: 'Animation'
 6Tooltip: 'Helperscripts to animate letters'
 7"""
 8import bpy
 9import random
10
11def textToSingleLetters(text="Hallo", x_start=0, y_start=0):
12    """ A given text line is divided in single letters (objects). """
13    counter = 1
14    kerning = .1
15    pos_next_x = 0
16    for letter in text:
17        name = "row_%s_%s_%s" % (y_start, counter, letter)
18        myFontCurve = bpy.data.curves.new(type="FONT", name=name)
19        myFontOb = bpy.data.objects.new(name, myFontCurve)
20        myFontOb.location = (x_start + pos_next_x, y_start, 0)       
21        myFontOb.data.body = letter
22        bpy.context.collection.objects.link(myFontOb)
23        counter += 1
24        pos_next_x = pos_next_x + myFontOb.dimensions.x + kerning
25 
26def defineEndPosition():
27    """ Register endposition of all text objects. 
28
29        This is the Position of each letter after creation.
30    """
31    data = {}
32    all = [item.name for item in bpy.data.objects]
33    for name in all:
34        if name[0:3] == "row":
35            obj = bpy.data.objects[name]
36            data[name] = [(obj.location.x,
37                           obj.location.y,
38                           obj.location.z)]
39    return data
40
41def calcStartPosition(d=None):
42    """ Calculate random start position of all text objects. """
43
44    all = [item.name for item in bpy.data.objects]
45    for name in all:
46        if name[0:3] == "row":                
47            obj = bpy.data.objects[name]
48            randX = round(random.uniform(-4, 4),3)
49            randY = round(random.uniform(10, 30),3)
50            randZ = round(random.uniform(10, 30),3)
51            d[name].append((randX, randY, randZ))
52    return d
53
54def calcStartEndFrames(d=None, startFrame=10, endFrame=190):
55    """ Calculate random startframe for each object. """
56
57    all = [item.name for item in bpy.data.objects]
58    for name in all:
59        if name[0:3] == "row":
60            x1 = int(random.uniform(10, 190))
61            x2 = int(random.uniform(10, 190))
62            if x1 > x2:
63                startFrame = x2
64                endFrame = x1
65            else:
66                startFrame = x1
67                endFrame = x2
68                
69            obj = bpy.data.objects[name]
70            d[name].append(startFrame)
71            d[name].append(endFrame)
72
73    return d
74
75def setkeyframes(d=None):
76    """ One line describing the task of this function  """
77    all = [item.name for item in bpy.data.objects]
78    for name in all:
79        if name[0:3] == "row":
80            obj = bpy.data.objects[name]
81            obj.location = d[name][0]
82            obj.keyframe_insert(data_path='location', frame=d[name][3])
83            obj.location = d[name][1]
84            obj.keyframe_insert(data_path='location', frame=d[name][2])
85           
86if __name__ == '__main__':
87    bpy.ops.object.select_by_type(type='FONT')
88    bpy.ops.object.delete()
89    textToSingleLetters("Blender", y_start=-1, x_start=-2)
90    textToSingleLetters("Summer-Summerschool", y_start=0, x_start=-2)
91    textToSingleLetters("Mannheim-2019", y_start=1, x_start=-2)
92
93    d = defineEndPosition()
94    d = calcStartPosition(d)
95    d = calcStartEndFrames(d)
96    setkeyframes(d)

Zeile(n)

Anmerkung

54

Die Start- und Ende-Frames berechnen.

58-67

Damit der Start-Wert größer als der Ende-Wert ist, wird noch

ein Vergleich durchgeführt.

70-71

Beide Werte werden im Dictionary gespeichert.

75-84

Alle Werte aus dem Dictionary werden nun verwendet um die

Start- und Ende-Postionen der Objekte zu definieren.

Animation testen

Die Animation kann nun getestet werden. Wenn alles zufriedenstellend läuft, kann daraus ein Film erstellt werden. Aber das ist schon wieder ein anderes Thema …