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
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!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). """

    counter = 1
    kerning = .1
    pos_next_x = 0
    for letter in text:
        name = "row_%s_%s" % (y_start, counter)
        myFontCurve = bpy.data.curves.new(type="FONT", name=name)
        myFontOb = bpy.data.objects.new(name, myFontCurve)
        myFontOb.location = (x_start + pos_next_x, y_start, 0)
        myFontOb.data.body = letter
        bpy.context.collection.objects.link(myFontOb)
        counter += 1
        pos_next_x = pos_next_x + myFontOb.dimensions.x + kerning


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__':

    bpy.ops.object.select_by_type(type='FONT')
    bpy.ops.object.delete()
    textToSingleLetters("Python", y_start=-1, x_start=-2)
    textToSingleLetters("Blender", y_start=0, x_start=-2)
    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
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!bpy
"""
Name: 'Flying Letters'
Blender: 2.8
Group: 'Animation'
Tooltip: 'Helperscripts to animate letters'
"""
import bpy
import random

def textToSingleLetters(text="Hallo", x_start=0, y_start=0):
    """ A given text line is divided in single letters (objects). """
    counter = 1
    kerning = .1
    pos_next_x = 0
    for letter in text:
        name = "row_%s_%s" % (y_start, counter)
        myFontCurve = bpy.data.curves.new(type="FONT", name=name)
        myFontOb = bpy.data.objects.new(name, myFontCurve)
        myFontOb.location = (x_start + pos_next_x, y_start, 0)       
        myFontOb.data.body = letter
        bpy.context.collection.objects.link(myFontOb)
        counter += 1
        pos_next_x = pos_next_x + myFontOb.dimensions.x + kerning
 
def defineEndPosition():
    """ Register endposition of all text objects. 

        This is the Position of each letter after creation.
    """
    data = {}
    all = [item.name for item in bpy.data.objects]
    for name in all:
        if name[0:3] == "row":
            obj = bpy.data.objects[name]
            data[name] = [(obj.location.x,
                           obj.location.y,
                           obj.location.z)]
    return data

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

    all = [item.name for item in bpy.data.objects]
    for name in all:
        if name[0:3] == "row":                
            obj = bpy.data.objects[name]
            randX = round(random.uniform(-4, 4),3)
            randY = round(random.uniform(10, 30),3)
            randZ = round(random.uniform(10, 30),3)
            d[name].append((randX, randY, randZ))
    return d

def calcStartEndFrames(d=None, startFrame=10, endFrame=190):
    """ Calculate random startframe for each object. """
    pass


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

if __name__ == '__main__':
    bpy.ops.object.select_by_type(type='FONT')
    bpy.ops.object.delete()
    textToSingleLetters("Python", y_start=-1, x_start=-2)
    textToSingleLetters("Blender", y_start=0, x_start=-2)
    textToSingleLetters("Blend4Web", y_start=1, x_start=-2)

    d = defineEndPosition()
    d = calcStartPosition(d)
    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
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#!bpy
"""
Name: 'Flying Letters'
Blender: 2.8
Group: 'Animation'
Tooltip: 'Helperscripts to animate letters'
"""
import bpy
import random

def textToSingleLetters(text="Hallo", x_start=0, y_start=0):
    """ A given text line is divided in single letters (objects). """
    counter = 1
    kerning = .1
    pos_next_x = 0
    for letter in text:
        name = "row_%s_%s_%s" % (y_start, counter, letter)
        myFontCurve = bpy.data.curves.new(type="FONT", name=name)
        myFontOb = bpy.data.objects.new(name, myFontCurve)
        myFontOb.location = (x_start + pos_next_x, y_start, 0)       
        myFontOb.data.body = letter
        bpy.context.collection.objects.link(myFontOb)
        counter += 1
        pos_next_x = pos_next_x + myFontOb.dimensions.x + kerning
 
def defineEndPosition():
    """ Register endposition of all text objects. 

        This is the Position of each letter after creation.
    """
    data = {}
    all = [item.name for item in bpy.data.objects]
    for name in all:
        if name[0:3] == "row":
            obj = bpy.data.objects[name]
            data[name] = [(obj.location.x,
                           obj.location.y,
                           obj.location.z)]
    return data

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

    all = [item.name for item in bpy.data.objects]
    for name in all:
        if name[0:3] == "row":                
            obj = bpy.data.objects[name]
            randX = round(random.uniform(-4, 4),3)
            randY = round(random.uniform(10, 30),3)
            randZ = round(random.uniform(10, 30),3)
            d[name].append((randX, randY, randZ))
    return d

def calcStartEndFrames(d=None, startFrame=10, endFrame=190):
    """ Calculate random startframe for each object. """

    all = [item.name for item in bpy.data.objects]
    for name in all:
        if name[0:3] == "row":
            x1 = int(random.uniform(10, 190))
            x2 = int(random.uniform(10, 190))
            if x1 > x2:
                startFrame = x2
                endFrame = x1
            else:
                startFrame = x1
                endFrame = x2
                
            obj = bpy.data.objects[name]
            d[name].append(startFrame)
            d[name].append(endFrame)

    return d

def setkeyframes(d=None):
    """ One line describing the task of this function  """
    all = [item.name for item in bpy.data.objects]
    for name in all:
        if name[0:3] == "row":
            obj = bpy.data.objects[name]
            obj.location = d[name][0]
            obj.keyframe_insert(data_path='location', frame=d[name][3])
            obj.location = d[name][1]
            obj.keyframe_insert(data_path='location', frame=d[name][2])
           
if __name__ == '__main__':
    bpy.ops.object.select_by_type(type='FONT')
    bpy.ops.object.delete()
    textToSingleLetters("Blender", y_start=-1, x_start=-2)
    textToSingleLetters("Summer-Summerschool", y_start=0, x_start=-2)
    textToSingleLetters("Mannheim-2019", y_start=1, x_start=-2)

    d = defineEndPosition()
    d = calcStartPosition(d)
    d = calcStartEndFrames(d)
    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 …