Saturday, January 05, 2008

Blender Python script to automate the creation of closing credits

Here is a sample Blender Python script to automate the creation of closing credits screen from a text file. In addition to closing credits, you can also use this script to scroll text.

The text file is read line by line, and a corresponding Text3d object is created, which will in turn become a child of an Empty object.
Key frames are created to move the location of the Empty object to scroll.
The scroll speed can be adjusted by changing the end frame value (nEndFrame).




Here is the sample video I made using this script.





To use this the code, you need the following three files:



closingCredits.py

textFile.py

closingCredits.txt



Put closingCredits.py and textFile.py in Blender's scripts directory.
Edit closingCredits.txt using a text editor, and and put it in /tmp.
--- BEGIN closingCredits.py ---


#!BPY

"""
Name: 'Closing Credits generation'
Blender: 244
Group: 'Animation'
Tooltip: 'Generate Closing Credits from a text file.'
"""

__author__ = "Hide Winston Inada"
__version__ = "0.9.1 Jan 05, 2008"

__bpydoc__ = """\
This script generates closing credits from a text file.
"""

# $Id: $
# ***** BEGIN GPL LICENSE BLOCK *****
# Script Copyright (C) 2007, Hide Winston Inada, hideyuki _at_ gmail.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# ***** END GPL LICENCE BLOCK *****

# ***** Blender modules *****
import Blender
from Blender import Window
from Blender import NMesh
from Blender import Object
from Blender import Mesh
from Blender import Scene
from Blender import Text3d
import bpy

# ***** Python modules *****
import math

# ***** Hide's helper modules *****
import textFile

# ***** Configurable parameters
sClosingCreditsPath = "/tmp/closingCredits.txt"
# this may map to c:\tmp under MS Windows

nNewStartFrame = 1
nNewCurrentFrame = 1
nNewEndFrame = 600

nSpaceBetweenLinesY = 1

# ***** Code start *****

def main():
# Standard start up code
print "\nStarting closingCredits.py"
sce = bpy.data.scenes.active
activeObject = sce.objects.active

# Read text file
aClosingCredits = textFile.readFileToList(sClosingCreditsPath)
if(aClosingCredits == None):
print "Error in reading the closing credits file."
print "Check to make sure that it is located at"
print sClosingCreditsPath
return

nNoLines = len(aClosingCredits)
if(nNoLines < 1):
print "The file " + sClosingCreditsPath + " is empty."
return
else:
print (str(nNoLines) + " lines have been read")

nOriginalStartFrame = Blender.Get('staframe')
nOriginalCurrentFrame = Blender.Get('curframe')
nOriginalEndFrame = Blender.Get('endframe')

Blender.Set('curframe', nNewCurrentFrame)

cxt = sce.getRenderingContext()
cxt.startFrame(nNewStartFrame)
cxt.endFrame(nNewEndFrame)

Window.RedrawAll()

nResult = Blender.Get('staframe')
if(nNewStartFrame != nResult) :
print("Error in setting the start frame")
return

nResult = Blender.Get('endframe')
if(nNewEndFrame != nResult) :
print("Error in setting the end frame")
return

nResult = Blender.Get('curframe')
if(nNewCurrentFrame != nResult) :
print("Error in setting the current frame")
return

# create an empty object
owEmpty = Blender.Object.New('Empty')
sce.objects.link(owEmpty)
owEmpty.setName('emptyParent')

aChildList = []
i = 0
for i in range(0, i+nNoLines) :

# create Data object for text
textDO = Text3d.New("textDataObj" + str(i))
textDO.setText(aClosingCredits[i])

# create object wrapper for text
ow = sce.objects.new(textDO)
ow.setName("textObjectWrapper" + str(i))
aChildList.append(ow)
ow.LocX = 0
ow.LocY = -nSpaceBetweenLinesY * i
ow.LocZ = 0

# Make Empty object the parent object for all text objects
owEmpty.makeParent(aChildList)

obj = owEmpty

i = 0
Blender.Set('curframe', nNewStartFrame)
obj.LocY = 0
obj.insertIpoKey(Object.IpoKeyTypes.LOCROTSIZE)

Blender.Set('curframe', nNewEndFrame)
obj.LocY = nNoLines * nSpaceBetweenLinesY
obj.insertIpoKey(Object.IpoKeyTypes.LOCROTSIZE)

ow.makeDisplayList()
Window.RedrawAll()

print ("Completed")
# end main

main()



--- END closingCredits.py ---



--- BEGIN textFile.py ---


# $Id: $
# ***** BEGIN GPL LICENSE BLOCK *****
# Copyright (C) 2008, Hide Winston Inada, hideyuki _at_ gmail.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# ***** END GPL LICENCE BLOCK *****

def readFileToList(sFilePath, bRStrip=True):
# Var
aText = []

# Code
try:
f=open(sFilePath, 'r')
except IOError:
print("Cannot open " + sFilePath)
return(None)
else:
try:
while (True) :
sReadLine = f.readline()
if(sReadLine == '') :
break

if(bRStrip == True) :
sReadLine = sReadLine.rstrip()
aText.append(sReadLine)

except IOError:
print("Error while reading " + sFilePath)
f.close()
return(None)
else:
f.close()
return(aText)

--- END textFile.py ---

--- BEGIN closingCredits.txt ---


Blender Closing Credits Generation Demo



Directed by Hide Inada


Produced by Hide Inada



Sample output




CAST

Role 1 Actor1
Role 2 Actor2
Role 3 Actor3
Role 4 Actor4
Role 5 Actor5
Role 6 Actor6
Role 7 Actor7
Role 8 Actor8
Role 9 Actor9
Role 10 Actor10
Role 11 Actor11
Role 12 Actor12
Role 13 Actor13
Role 14 Actor14
Role 15 Actor15
Role 16 Actor16
Role 17 Actor17
Role 18 Actor18
Role 19 Actor19
Role 20 Actor20
Role 21 Actor21
Role 22 Actor22
Role 23 Actor23
Role 24 Actor24
Role 25 Actor25
Role 26 Actor26
Role 27 Actor27
Role 28 Actor28
Role 29 Actor29
Role 30 Actor30
Role 31 Actor31
Role 32 Actor32
Role 33 Actor33
Role 34 Actor34
Role 35 Actor35
Role 36 Actor36
Role 37 Actor37
Role 38 Actor38
Role 39 Actor39




STAFF

Staff Role1 Staff1
Staff Role2 Staff2
Staff Role3 Staff3
Staff Role4 Staff4
Staff Role5 Staff5
Staff Role6 Staff6
Staff Role7 Staff7
Staff Role8 Staff8
Staff Role9 Staff9
Staff Role10 Staff10
Staff Role11 Staff11
Staff Role12 Staff12
Staff Role13 Staff13
Staff Role14 Staff14
Staff Role15 Staff15
Staff Role16 Staff16
Staff Role17 Staff17
Staff Role18 Staff18
Staff Role19 Staff19
Staff Role20 Staff20
Staff Role21 Staff21
Staff Role22 Staff22
Staff Role23 Staff23
Staff Role24 Staff24
Staff Role25 Staff25
Staff Role26 Staff26
Staff Role27 Staff27
Staff Role28 Staff28
Staff Role29 Staff29
Staff Role30 Staff30
Staff Role31 Staff31
Staff Role32 Staff32
Staff Role33 Staff33
Staff Role34 Staff34
Staff Role35 Staff35
Staff Role36 Staff36
Staff Role37 Staff37
Staff Role38 Staff38
Staff Role39 Staff39


Copyright (C) 2008 Hide Winston Inada.
All rights reserved.

--- END closingCredits.txt ---

Wednesday, January 02, 2008

Demo Blender Python script to automate the keyframe insertion

Here is a demo Blender Python script to automate the keyframe insertion.
In this demo, keyframes are created at the object level, or IPO level (instead of vertex level).
In the sample video below, I used the monkey mesh model called Suzanne which comes with Blender.
This scripts adjusts the location and rotation at each keyframe.





--- BEGIN Script ---


#!BPY

"""
Name: 'Automated IPO keyframe insertion demo'
Blender: 244
Group: 'Animation'
Tooltip: 'Demo for automated IPO keyframe insertion using Python'
"""

__author__ = "Hide Winston Inada"
__version__ = "0.9 2008-1-03"

__bpydoc__ = """\
This script is a demo to show automated IPO keyframe insertion using Python.
"""

# $Id: $
# ***** BEGIN GPL LICENSE BLOCK *****
# Script Copyright (C) 2007, Hide Winston Inada, hideyuki _at_ gmail.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# ***** END GPL LICENCE BLOCK *****

import math

import Blender
from Blender import Window
from Blender import NMesh
from Blender import Object

import bpy

# Variables
nNewStartFrame = 1
nNewCurrentFrame = 1
nNewEndFrame = 120

nNoFrames = nNewEndFrame - nNewStartFrame + 1
nFirstKeyFrame = nNewStartFrame - 1 + nNoFrames/4
nSecondKeyFrame = nNewStartFrame - 1 + (nNoFrames/4)*2
nThirdKeyFrame = nNewStartFrame - 1 + (nNoFrames/4)*3

# Debug print out
print ("")
print ("Starting demo for automated IPO keyframe insertion using Python")
print ("Configurable parameter listing:")
print ("Start frame : " + str(nNewStartFrame))
print ("End frame : " + str(nNewEndFrame))
print ("Current frame : " + str(nNewCurrentFrame))
print ("Number of frames : " + str(nNoFrames))
print ("First keyframe : " + str(nFirstKeyFrame))
print ("Second keyframe : " + str(nSecondKeyFrame))
print ("Third keyframe : " + str(nThirdKeyFrame))
# Debug print out end

activeScene = bpy.data.scenes.active
activeObject = activeScene.objects.active

# Setting start, end, current frames
nOriginalStartFrame = Blender.Get('staframe')
# print("Original start frame : " + str(nOriginalStartFrame))

nOriginalCurrentFrame = Blender.Get('curframe')
# print("Original current frame : " + str(nOriginalCurrentFrame))

nOriginalEndFrame = Blender.Get('endframe')
# print("Original end frame : " + str(nOriginalEndFrame))

Blender.Set('curframe', nNewCurrentFrame)

cxt = activeScene.getRenderingContext()
cxt.startFrame(nNewStartFrame)
cxt.endFrame(nNewEndFrame)

Window.RedrawAll()

# Verifying to see if frames are set correctly
nResult = Blender.Get('staframe')
if(nNewStartFrame != nResult) :
print("Error in setting the start frame")

nResult = Blender.Get('endframe')
if(nNewEndFrame != nResult) :
print("Error in setting the end frame")

nResult = Blender.Get('curframe')
if(nNewCurrentFrame != nResult) :
print("Error in setting the current frame")

# Keyframe insertion
obj = activeObject

Blender.Set('curframe', nNewStartFrame)
obj.LocX = 0
obj.LocY = 0
obj.LocZ = 0
obj.RotZ = math.radians(90)
obj.insertIpoKey(Object.IpoKeyTypes.LOCROTSIZE)

Blender.Set('curframe', nNewEndFrame)
obj.LocX = 0
obj.LocY = 0
obj.LocZ = 0
obj.RotZ = math.radians(360+90)
obj.insertIpoKey(Object.IpoKeyTypes.LOCROTSIZE)

Blender.Set('curframe', nFirstKeyFrame)
obj.LocX = 4
obj.LocY = 0
obj.LocZ = 0
obj.RotZ = math.radians(180)
obj.insertIpoKey(Object.IpoKeyTypes.LOCROTSIZE)

Blender.Set('curframe', nSecondKeyFrame)
obj.LocX = 4
obj.LocY = 4
obj.LocZ = 0
obj.RotZ = math.radians(270)
obj.insertIpoKey(Object.IpoKeyTypes.LOCROTSIZE)

Blender.Set('curframe', nThirdKeyFrame)
obj.LocX = 0
obj.LocY = 4
obj.LocZ = 0
obj.RotZ = math.radians(360)
obj.insertIpoKey(Object.IpoKeyTypes.LOCROTSIZE)

# Finalization
print("Completed")

# References
# 1. For setting start, end frames, see:
# http://blenderartists.org/forum/archive/index.php/t-62993.html




--- END Script ---