Openshot Blender

Posted on  by admin
  1. Openshot Blender Slow
  2. Openshot Blender Not Working
  3. Openshot Blender No Frame Was Found
  4. Openshot Blender Path

Réaliser des titres animés pour OpenShot à l’aide de Blender

Retrouvez les explications complètes dans Linux Pratique 77

On-premise open-source video editing solution that helps users edit videos and add effects with webcam, screen and audio capture. Open-source video editing tool for Windows, Mac and Linux users which helps with 3D animated titles, audio mixing/editing, frame accuracy, clip resizing, desktop integration and more.

Zip file of the animated title

Softtext.zip

Animation Idea and automation

The first thing to do consists in creating an title animation with Blender. You can grab ideas all over the net. Just make a beautiful title in 3D wich is animated :-).

After that, you need to automate it using the API of blender. You can read lots of tutorial, watch amazing videos too. This is the big part of the work : create and automate.

It remains the integration in Openshot. That’s I’m going to explain here, based on an example.

Soft text animation and automation

Blender capture of the working blend file

The chosen animation on this example, is made of a falling text on a rough surface. The text is made of a soft material. So when reaching the ground, the text bounces and trembles before stopping. In the simulation, we can add a cylinder to show more physical effects.

Source code of the automation (using Blender API)

In this source code, we manage the possibility to hide the red cylinder and its physical effect on our soft text. The control variable is name “cylinder”

import bpy
from bpy.props import *
from math import pi
cylinder ='1'
#http://www.sebastianbauer.name/archive/117
def moveToLayer( object, layer ):
layers = [False]*20
layers[layer] = True
object.layers = layers
def createSoftText(title,extrude,bevel_depth,spacemode,textsize,width,font):
if cylinder'1':
bpy.data.objects['Cylinder'].hide_render = False
bpy.data.objects['Cylinder'].hide = False
bpy.ops.object.select_all(action='DESELECT')
#selecting Ground
bpy.context.scene.objects.active = bpy.data.objects['Cylinder']
bpy.context.scene.objects.active.select = True
#if bpy.data.objects['Ground'].modifiers.keys()[0] != 'Collision':
if bpy.data.objects['Cylinder'].modifiers.find('Collision') -1:
#print('collision = empty')
bpy.ops.object.modifier_add(type='COLLISION')
else:
print('OK')
else:
bpy.ops.object.select_all(action='DESELECT')
#selecting Cylinder
bpy.context.scene.objects.active = bpy.data.objects['Cylinder']
bpy.context.scene.objects.active.select = True
if bpy.data.objects['Cylinder'].modifiers.find('Collision') != -1:
bpy.ops.object.modifier_remove(modifier='Collision')
bpy.data.objects['Cylinder'].hide = True
bpy.data.objects['Cylinder'].hide_render = True
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.text_add(view_align=False, enter_editmode=False,location=(0, 0, 0), rotation=(0, 0, 0))
ActiveObjectText = bpy.context.scene.objects.active
newtext = bpy.context.scene.objects.active
#erasing previous objects
if bpy.context.scene.objects.active.name != 'Text':
bpy.ops.object.select_all(action='DESELECT')
#selecting and erasing Text
bpy.context.scene.objects.active = bpy.data.objects['Text']
bpy.context.scene.objects.active.select = True
bpy.ops.object.delete(use_global=False)
bpy.ops.object.select_all(action='DESELECT')
#need to delete other objects
bpy.ops.object.select_all(action='DESELECT')
#selecting and erasing Turbulence field
bpy.context.scene.objects.active = bpy.data.objects['Enveloppe2']
bpy.context.scene.objects.active.select = True
bpy.ops.object.delete(use_global=False)
#selecting newText
bpy.context.scene.objects.active = newtext
bpy.context.scene.objects.active.select = True
#naming/renaming the text
bpy.context.scene.objects.active.name = 'Text';
bpy.context.scene.objects.active = bpy.data.objects['Text']
#rotating text
ActiveObjectText.rotation_euler[0]=0.0 #xaxis
ActiveObjectText.rotation_euler[1]=0.0 #yaxis
ActiveObjectText.rotation_euler[2]=0.0 #zaxis
ActiveObjectText.location[0]=0
ActiveObjectText.location[1]=-9.75
ActiveObjectText.location[2]=5 #dur to shadow on the ground
#changing text
ActiveObjectText.data.body = title
#centering text
ActiveObjectText.data.align= spacemode
#extrude text
ActiveObjectText.data.extrude=extrude
#bevel text
ActiveObjectText.data.bevel_depth = bevel_depth
ActiveObjectText.data.bevel_resolution = 5
#text size
ActiveObjectText.data.size = textsize
bpy.context.scene.objects.active.data.space_character = width
bpy.context.scene.objects.active.data.font = font
#convert to mesh to apply effect
bpy.ops.object.convert(target='MESH', keep_original=False)
#put origin to center of text
#bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN')
# Don't use Median, because it does not always put the origin to the center!
bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN', center='BOUNDS')
#affect material
ActiveObjectText.data.materials.append(bpy.data.materials['MAT_PRE_Obsidian'])
#copy the pre loopecut cube
bpy.ops.object.select_all(action='DESELECT')
#obsolete
#bpy.ops.object.select_name(name='Enveloppe')
bpy.context.scene.objects.active = bpy.context.scene.objects['Enveloppe']
#activate in 3D
bpy.context.scene.objects.active.select = True
bpy.ops.object.duplicate(linked=False, mode='TRANSLATION')
#bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={'linked':False, 'mode':'TRANSLATION'}, TRANSFORM_OT_translate={'value':(0, 0, 0), 'constraint_axis':(False, False, False), 'constraint_orientation':'GLOBAL', 'mirror':False, 'proportional':'DISABLED', 'proportional_edit_falloff':'SMOOTH', 'proportional_size':1, 'snap':False, 'snap_target':'CLOSEST', 'snap_point':(0, 0, 0), 'snap_align':False, 'snap_normal':(0, 0, 0), 'texture_space':False, 'release_confirm':False})
ActiveObjectEnveloppe = bpy.context.scene.objects.active
ActiveObjectEnveloppe.name = 'Enveloppe2'
ActiveObjectEnveloppe.draw_type = 'WIRE'
ActiveObjectEnveloppe.hide_render = True
#need to be on the visible layer to do duplication?
#moving object
ActiveObjectEnveloppe.location[0]=0
ActiveObjectEnveloppe.location[1]=-9.75
ActiveObjectEnveloppe.location[2]=5
# mo ve to layer 0 (first one)
#moveToLayer(ActiveObjectEnveloppe,0)
#adjust size of existed envelope to text
IncrementX = 0.3
IncrementY = 0.3
IncrementZ = 0.15
ActiveObjectEnveloppe.dimensions = (ActiveObjectText.dimensions[0]+IncrementX),(ActiveObjectText.dimensions[1]+IncrementY), (ActiveObjectText.dimensions[2]+IncrementZ)
#bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN', center='MEDIAN')
bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN', center='BOUNDS')
bpy.ops.object.modifier_add(type='SOFT_BODY')
#link text to enveloppe
bpy.ops.object.select_all(action='DESELECT')
#obsolete
#bpy.ops.object.select_name(name='Enveloppe')
bpy.context.scene.objects.active = ActiveObjectText
#activate in 3D
bpy.context.scene.objects.active.select = True
bpy.ops.object.modifier_add(type='MESH_DEFORM')
#configuring mesh deform
ActiveObjectText.modifiers['MeshDeform'].object = ActiveObjectEnveloppe
ActiveObjectText.modifiers['MeshDeform'].precision = 6 #<6 does not work!!! grid precision?
#binding text to cube
bpy.ops.object.meshdeform_bind(modifier='MeshDeform')
#softbody configuration
ActiveObjectEnveloppe.soft_body.use_goal=False
ActiveObjectEnveloppe.soft_body.use_stiff_quads = True
ActiveObjectEnveloppe.soft_body.plastic=10
ActiveObjectEnveloppe.data.update()
bpy.ops.ptcache.free_bake_all() # erase baked dynamics
bpy.ops.ptcache.bake_all() # bake dynamics : take time but needed before rendering animation
font = bpy.data.fonts['Bfont'] #don't forget to save datablock with Bfont :-)
extrude = 0.1
bevel_depth = 0.01
spacemode = 'CENTER'
text_size = 1.0
width = 1.0
createSoftText(title,extrude,bevel_depth,spacemode,text_size,width,font)

Result image (number 85 in animation)

Making of

Integration

How it works

Now the animation is full fonctionning in Blender (You can try it with the blend file embedded in the ZIP archive). We have to use it with Openshot. Before we need to understand how an animation made with Blender can be used in Openshot.

For that, Openshot use the following synoptic :

Openshot uses 4 files to be able to propose to the user a new 3D title :

  • An icon file which represents the final render of the title in th e Openshot GUI
  • An XML file which contains the GUI interface for configuring the 3D title
  • A blender file, the main file, which will be use by Blender to generate the animation
  • An python file which contains the core code for modifying the blender file according to configuration made by the user in the GUI. All the modification will be given to the blend file when rendering.
    These files are located in different directories under /usr/share/pyshared/openshot/blender :
$ tree -d /usr/share/pyshared/openshot/blender
/usr/share/pyshared/openshot/blender
├── blend
├── earth
├── icons
└── scripts
4 directories

The « blender » directory contains the « XML » files of the titles GUI configurators. The « blend » directory contains originals Blender files which embed animation on a generic text. The « earth » directory contains NASA images for the realistic earth title. The “icons” directory contains icons for the title GUI. The “scripts” directory contains python files which link Openshot to Blender for rendering. Theses files are the most difficult to write. They contains all the automation of the animation, and the Blender API commands which modify the original blender file to suit the user’s configuration.

So we need to create these files for our soft text animation.

When the 3D Title is configured, you can launched rendering. At this time, Openshot is calling Blender in commandline mode like that :

Blender command: /home/yann/Téléchargements/blender-2.62-linux-glibc27-x86_64/blender -b '/usr/lib/pymodules/python2.7/openshot/blender/blend/explode.blend' -P '/home/yann/.openshot/blender/cdd6b89e-1439-11e2-a257-0024d6b0a314/explode.py'
update_image: /home/yann/.openshot/blender/cdd6b89e-1439-11e2-a257-0024d6b0a314/TitleFileName0075.png
Blender render thread finished

Blender is run with two parameters :

  • « -b » indicates the blend file to use and render in background. This option allows to use Openshot during the render ;
  • « -P » indicates the python script to be executed with the blend file.

The sample image is written in a subdirectory of your home « /.openshot/blender ».

Creation from previous animation

Except for the icon file, we will use existing files from the Openshot distribution software to create the new ones.

Here is our new icon :

Other file are created by copying existing files :

$ cp /home/yann/Documents/articles_lpmag/article_titre_openshot/images/title_icon.png ./icons/softtext.png
$ cp fly_by_1.xml softtext.xml
$ cp /home/yann/blender/softtext/mysofttext_openshot.blend blend/softtext.blend
$ cp scripts/fly_by_1.py scripts/softtext.py

Modification of the XML file for interface

We modify the head of the file to suit the new animation :

<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<!DOCTYPE openshot-effect>
<effect>
<title translatable='True'>Falling Soft Text</title>
<description translatable='True'>The soft boby title is on the ground</description>
<icon>softtext.png</icon>
<category>Video</category>
<service>softtext.blend</service>

And in order to manage the cylinder in the animation, we add a dropdown menu in th e GUI :

Blender executable file path
<param name='cylinder_on_off' type='dropdown' description='>
<values>
<value name='Yes' num='1'/>
<value name='No' num='0'/>
</values>
<default>1</default>

Finally modify the animation duration to fit you blend file animation length :

<param name='end_frame' type='spinner' description='>
<min>144</min>
<max>144</max>
<default>144</default>
</param>

Even if the new title is not yet operational, you can see the new GUI for our sofftext by launching Openshot :

Modification of the python script

We need to modify the python script to match the new 3D title.

This file is globally divided in 3 parts :

  • Inclusions and funtions ;
  • Initialisation of all the parameters ;
  • Modification of the Blender file parameters from the Openshot GUI.

Just after the “loadfont” function we put our “createSoftText” function

def createSoftText(title,extrude,bevel_depth,spacemode,textsize,width,font):
if cylinder'1':
bpy.data.objects['Cylinder'].hide_render = False
bpy.data.objects['Cylinder'].hide = False
bpy.ops.object.select_all(action='DESELECT')
#selecting Ground
bpy.context.scene.objects.active = bpy.data.objects['Cylinder']
bpy.context.scene.objects.active.select = True
#if bpy.data.objects['Ground'].modifiers.keys()[0] != 'Collision':
if bpy.data.objects['Cylinder'].modifiers.find('Collision') -1:
#print('collision = empty')
bpy.ops.object.modifier_add(type='COLLISION')
#else:
#print('OK')
else:
bpy.ops.object.select_all(action='DESELECT')
#selecting Cylinder
bpy.context.scene.objects.active = bpy.data.objects['Cylinder']
bpy.context.scene.objects.active.select = True
if bpy.data.objects['Cylinder'].modifiers.find('Collision') != -1:
bpy.ops.object.modifier_remove(modifier='Collision')
bpy.data.objects['Cylinder'].hide = True
bpy.data.objects['Cylinder'].hide_render = True
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.text_add(view_align=False, enter_editmode=False,location=(0, 0, 0), rotation=(0, 0, 0))
ActiveObjectText = bpy.context.scene.objects.active
newtext = bpy.context.scene.objects.active
#erasing previous objects
if bpy.context.scene.objects.active.name != 'Text':
bpy.ops.object.select_all(action='DESELECT')
#selecting and erasing Text
bpy.context.scene.objects.active = bpy.data.objects['Text']
bpy.context.scene.objects.active.select = True
bpy.ops.object.delete(use_global=False)
bpy.ops.object.select_all(action='DESELECT')
#need to delete other objects
bpy.ops.object.select_all(action='DESELECT')
#selecting and erasing Turbulence field
bpy.context.scene.objects.active = bpy.data.objects['Enveloppe2']
bpy.context.scene.objects.active.select = True
bpy.ops.object.delete(use_global=False)
#selecting newText
bpy.context.scene.objects.active = newtext
bpy.context.scene.objects.active.select = True
#naming/renaming the text
bpy.context.scene.objects.active.name = 'Text';
bpy.context.scene.objects.active = bpy.data.objects['Text']
#rotating text
ActiveObjectText.rotation_euler[0]=0.0 #xaxis
ActiveObjectText.rotation_euler[1]=0.0 #yaxis
ActiveObjectText.rotation_euler[2]=0.0 #zaxis
ActiveObjectText.location[0]=0
ActiveObjectText.location[1]=-9.75
ActiveObjectText.location[2]=5 #dur to shadow on the ground
#changing text
ActiveObjectText.data.body = title
#centering text
ActiveObjectText.data.align= spacemode
#extrude text
ActiveObjectText.data.extrude=extrude
#bevel text
ActiveObjectText.data.bevel_depth = bevel_depth
ActiveObjectText.data.bevel_resolution = 5
#text size
ActiveObjectText.data.size = textsize
bpy.context.scene.objects.active.data.space_character = width
bpy.context.scene.objects.active.data.font = font
#convert to mesh to apply effect
bpy.ops.object.convert(target='MESH', keep_original=False)
#put origin to center of text
#bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN')
# Don't use Median, because it does not always put the origin to the center!
bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN', center='BOUNDS')
#affect material
ActiveObjectText.data.materials.append(bpy.data.materials['MAT_PRE_Obsidian'])
#copy the pre loopecut cube
bpy.ops.object.select_all(action='DESELECT')
#obsolete
#bpy.ops.object.select_name(name='Enveloppe')
bpy.context.scene.objects.active = bpy.context.scene.objects['Enveloppe']
#activate in 3D
bpy.context.scene.objects.active.select = True
bpy.ops.object.duplicate(linked=False, mode='TRANSLATION')
#bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={'linked':False, 'mode':'TRANSLATION'}, TRANSFORM_OT_translate={'value':(0, 0, 0), 'constraint_axis':(False, False, False), 'constraint_orientation':'GLOBAL', 'mirror':False, 'proportional':'DISABLED', 'proportional_edit_falloff':'SMOOTH', 'proportional_size':1, 'snap':False, 'snap_target':'CLOSEST', 'snap_point':(0, 0, 0), 'snap_align':False, 'snap_normal':(0, 0, 0), 'texture_space':False, 'release_confirm':False})
ActiveObjectEnveloppe = bpy.context.scene.objects.active
ActiveObjectEnveloppe.name = 'Enveloppe2'
ActiveObjectEnveloppe.draw_type = 'WIRE'
ActiveObjectEnveloppe.hide_render = True
#need to be on the visible layer to do duplication?
#moving object
ActiveObjectEnveloppe.location[0]=0
ActiveObjectEnveloppe.location[1]=-9.75
ActiveObjectEnveloppe.location[2]=5
# mo ve to layer 0 (first one)
#moveToLayer(ActiveObjectEnveloppe,0)
#adjust size of existed envelope to text
IncrementX = 0.3
IncrementY = 0.3
IncrementZ = 0.15
ActiveObjectEnveloppe.dimensions = (ActiveObjectText.dimensions[0]+IncrementX),(ActiveObjectText.dimensions[1]+IncrementY), (ActiveObjectText.dimensions[2]+IncrementZ)
#bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN', center='MEDIAN')
bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN', center='BOUNDS')
bpy.ops.object.modifier_add(type='SOFT_BODY')
#link text to enveloppe
bpy.ops.object.select_all(action='DESELECT')
#obsolete
#bpy.ops.object.select_name(name='Enveloppe')
bpy.context.scene.objects.active = ActiveObjectText
#activate in 3D
bpy.context.scene.objects.active.select = True
bpy.ops.object.modifier_add(type='MESH_DEFORM')
#configuring mesh deform
ActiveObjectText.modifiers['MeshDeform'].object = ActiveObjectEnveloppe
ActiveObjectText.modifiers['MeshDeform'].precision = 6 #<6 does not work!!! grid precision?
#binding text to cube
bpy.ops.object.meshdeform_bind(modifier='MeshDeform')
#softbody configuration
ActiveObjectEnveloppe.soft_body.use_goal=False
ActiveObjectEnveloppe.soft_body.use_stiff_quads = True
ActiveObjectEnveloppe.soft_body.plastic=10
ActiveObjectEnveloppe.data.update()
bpy.ops.ptcache.free_bake_all() # erase baked dynamics
bpy.ops.ptcache.bake_all() # bake dynamics : take time but needed before rendering animation

Important : The two last lines bakes all the physics stuff which can be long. But if you don’t do that, your sample image will be false, because the history of the animation is not taken into account while Openshot makes render only for one frame for sample images.

After that, we need to add the new cylinder variable in the params area :

# Init all of the variables needed by this script. Because Blender executes
# this script, OpenShot will inject a dictionary of the required parameters
# before this script is executed.
params = {
'title' : 'Oh Yeah! OpenShot!',
'extrude' : 0.05,
'bevel_depth' : 0.01,
'spacemode' : 'CENTER',
'text_size' : 1,
'width' : 1.0,
'fontname' : 'Bfont',
'color' : [0.8,0.8,0.8],
'alpha' : 1.0,
'output_path' : '/tmp/',
'fps' : 24,
'quality' : 90,
'file_format' : 'PNG',
'color_mode' : 'RGBA',
'horizon_color' : [0, 0, 0],
'resolution_x' : 1920,
'resolution_y' : 1080,
'resolution_percentage' : 100,
'start_frame' : 20,
'end_frame' : 25,
'animation' : True,
}

The next step, is made of comments. We need to comment some old python stuff on unused text object :

Openshot Blender Slow

#text_object = bpy.data.curves['txtName1']
#text_object.extrude = params['extrude']
#text_object.bevel_depth = params['bevel_depth']
#text_object.body = params['title']
#text_object.align = params['spacemode']
#text_object.size = params['text_size']
#text_object.space_character = params['width']

Same thing for the font which is managed by the function now :

Next we call the main function with the GUI parameters :

# function call createSoftText(title,extrude,bevel_depth,spacemode,textsize,width,font,cylinder)
createSoftText(params['title'],params['extrude'],params['bevel_depth'],params['spacemode'],params['text_size'],params['width'], font, params['cylinder_on_off'])

Finally, we ajust the material pointer to the our text material in the blend file :

# Change the material settings (color, alpha, etc...)
#material_object = bpy.data.materials['Material.001']
material_object = bpy.data.materials['MAT_PRE_Obsidian'] #match the text material in Blend file

Here the full code of the softtext.py file

# OpenShot Video Editor is a program that creates, modifies, and edits video files.
# Copyright (C) 2009 Jonathan Thomas
#
# This file is part of OpenShot Video Editor (http://launchpad.net/openshot/).
#
# OpenShot Video Editor 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 3 of the License, or
# (at your option) any later version.
#
# OpenShot Video Editor 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.
#
# You should have received a copy of the GNU General Public License
# along with OpenShot Video Editor. If not, see <http://www.gnu.org/licenses/>.
# Import Blender's python API. This only works when the script is being
# run from the context of Blender. Blender contains it's own version of Python
# with this library pre-installed.
import bpy
# Load a font
def load_font(font_path):
'' Load a new TTF font into Blender, and return the font object ''
# get the original list of fonts (before we add a new one)
original_fonts = bpy.data.fonts.keys()
# load new font
bpy.ops.font.open(filepath=font_path)
# get the new list of fonts (after we added a new one)
for font_name in bpy.data.fonts.keys():
if font_name not in original_fonts:
return bpy.data.fonts[font_name]
# no new font was added
return None
def createSoftText(title,extrude,bevel_depth,spacemode,textsize,width,font,cylinder):
'' Create an animated falling softbody text ''
if cylinder'1':
bpy.data.objects['Cylinder'].hide_render = False
bpy.data.objects['Cylinder'].hide = False
bpy.ops.object.select_all(action='DESELECT')
#selecting Ground
bpy.context.scene.objects.active = bpy.data.objects['Cylinder']
bpy.context.scene.objects.active.select = True
#if bpy.data.objects['Ground'].modifiers.keys()[0] != 'Collision':
if bpy.data.objects['Cylinder'].modifiers.find('Collision') -1:
#print('collision = empty')
bpy.ops.object.modifier_add(type='COLLISION')
#else:
#print('OK')
else:
bpy.ops.object.select_all(action='DESELECT')
#selecting Cylinder
bpy.context.scene.objects.active = bpy.data.objects['Cylinder']
bpy.context.scene.objects.active.select = True
if bpy.data.objects['Cylinder'].modifiers.find('Collision') != -1:
bpy.ops.object.modifier_remove(modifier='Collision')
bpy.data.objects['Cylinder'].hide = True
bpy.data.objects['Cylinder'].hide_render = True
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.text_add(view_align=False, enter_editmode=False,location=(0, 0, 0), rotation=(0, 0, 0))
ActiveObjectText = bpy.context.scene.objects.active
newtext = bpy.context.scene.objects.active
#erasing previous objects
if bpy.context.scene.objects.active.name != 'Text':
bpy.ops.object.select_all(action='DESELECT')
#selecting and erasing Text
bpy.context.scene.objects.active = bpy.data.objects['Text']
bpy.context.scene.objects.active.select = True
bpy.ops.object.delete(use_global=False)
bpy.ops.object.select_all(action='DESELECT')
#need to delete other objects
bpy.ops.object.select_all(action='DESELECT')
#selecting and erasing Turbulence field
bpy.context.scene.objects.active = bpy.data.objects['Enveloppe2']
bpy.context.scene.objects.active.select = True
bpy.ops.object.delete(use_global=False)
#selecting newText
bpy.context.scene.objects.active = newtext
bpy.context.scene.objects.active.select = True
#naming/renaming the text
bpy.context.scene.objects.active.name = 'Text';
bpy.context.scene.objects.active = bpy.data.objects['Text']
#rotating text
ActiveObjectText.rotation_euler[0]=0.0 #xaxis
ActiveObjectText.rotation_euler[1]=0.0 #yaxis
ActiveObjectText.rotation_euler[2]=0.0 #zaxis
ActiveObjectText.location[0]=0
ActiveObjectText.location[1]=-9.75
ActiveObjectText.location[2]=5 #dur to shadow on the ground
#changing text
ActiveObjectText.data.body = title
#centering text
ActiveObjectText.data.align= spacemode
#extrude text
ActiveObjectText.data.extrude=extrude
#bevel text
ActiveObjectText.data.bevel_depth = bevel_depth
ActiveObjectText.data.bevel_resolution = 5
#text size
ActiveObjectText.data.size = textsize
bpy.context.scene.objects.active.data.space_character = width
bpy.context.scene.objects.active.data.font = font
#convert to mesh to apply effect
bpy.ops.object.convert(target='MESH', keep_original=False)
#put origin to center of text
#bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN')
# Don't use Median, because it does not always put the origin to the center!
bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN', center='BOUNDS')
#affect material
ActiveObjectText.data.materials.append(bpy.data.materials['MAT_PRE_Obsidian'])
#copy the pre loopecut cube
bpy.ops.object.select_all(action='DESELECT')
#obsolete
#bpy.ops.object.select_name(name='Enveloppe')
bpy.context.scene.objects.active = bpy.context.scene.objects['Enveloppe']
#activate in 3D
bpy.context.scene.objects.active.select = True
bpy.ops.object.duplicate(linked=False, mode='TRANSLATION')
#bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={'linked':False, 'mode':'TRANSLATION'}, TRANSFORM_OT_translate={'value':(0, 0, 0), 'constraint_axis':(False, False, False), 'constraint_orientation':'GLOBAL', 'mirror':False, 'proportional':'DISABLED', 'proportional_edit_falloff':'SMOOTH', 'proportional_size':1, 'snap':False, 'snap_target':'CLOSEST', 'snap_point':(0, 0, 0), 'snap_align':False, 'snap_normal':(0, 0, 0), 'texture_space':False, 'release_confirm':False})
ActiveObjectEnveloppe = bpy.context.scene.objects.active
ActiveObjectEnveloppe.name = 'Enveloppe2'
ActiveObjectEnveloppe.draw_type = 'WIRE'
ActiveObjectEnveloppe.hide_render = True
#need to be on the visible layer to do duplication?
#moving object
ActiveObjectEnveloppe.location[0]=0
ActiveObjectEnveloppe.location[1]=-9.75
ActiveObjectEnveloppe.location[2]=5
# mo ve to layer 0 (first one)
#moveToLayer(ActiveObjectEnveloppe,0)
#adjust size of existed envelope to text
IncrementX = 0.3
IncrementY = 0.3
IncrementZ = 0.15
ActiveObjectEnveloppe.dimensions = (ActiveObjectText.dimensions[0]+IncrementX),(ActiveObjectText.dimensions[1]+IncrementY), (ActiveObjectText.dimensions[2]+IncrementZ)
#bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN', center='MEDIAN')
bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN', center='BOUNDS')
bpy.ops.object.modifier_add(type='SOFT_BODY')
#link text to enveloppe
bpy.ops.object.select_all(action='DESELECT')
#obsolete
#bpy.ops.object.select_name(name='Enveloppe')
bpy.context.scene.objects.active = ActiveObjectText
#activate in 3D
bpy.context.scene.objects.active.select = True
bpy.ops.object.modifier_add(type='MESH_DEFORM')
#configuring mesh deform
ActiveObjectText.modifiers['MeshDeform'].object = ActiveObjectEnveloppe
ActiveObjectText.modifiers['MeshDeform'].precision = 6 #<6 does not work!!! grid precision?
#binding text to cube
bpy.ops.object.meshdeform_bind(modifier='MeshDeform')
#softbody configuration
ActiveObjectEnveloppe.soft_body.use_goal=False
ActiveObjectEnveloppe.soft_body.use_stiff_quads = True
ActiveObjectEnveloppe.soft_body.plastic=10
ActiveObjectEnveloppe.data.update()
bpy.ops.ptcache.free_bake_all() # erase baked dynamics
bpy.ops.ptcache.bake_all() # bake dynamics : take time but needed before rendering animation
# Debug Info:
# ./blender -b test.blend -P demo.py
# -b = background mode
# -P = run a Python script within the context of the project file
# Init all of the variables needed by this script. Because Blender executes
# this script, OpenShot will inject a dictionary of the required parameters
# before this script is executed.
params = {
'title' : 'Oh Yeah! OpenShot!',
'extrude' : 0.1,
'bevel_depth' : 0.02,
'spacemode' : 'CENTER',
'text_size' : 1.5,
'width' : 1.0,
'fontname' : 'Bfont',
'cylinder_on_off' : '1',
'color' : [0.8,0.8,0.8],
'alpha' : 1.0,
'output_path' : '/tmp/',
'fps' : 24,
'quality' : 90,
'file_format' : 'PNG',
'color_mode' : 'RGBA',
'horizon_color' : [0.57, 0.57, 0.57],
'resolution_x' : 1920,
'resolution_y' : 1080,
'resolution_percentage' : 100,
'start_frame' : 20,
'end_frame' : 25,
'animation' : True,
}
#INJECT_PARAMS_HERE
# The remainder of this script will modify the current Blender .blend project
# file, and adjust the settings. The .blend file is specified in the XML file
# that defines this template in OpenShot.
#----------------------------------------------------------------------------
# Modify Text / Curve settings
#print (bpy.data.curves.keys())
#text_object = bpy.data.curves['txtName1']
#text_object.extrude = params['extrude']
#text_object.bevel_depth = params['bevel_depth']
#text_object.body = params['title']
#text_object.align = params['spacemode']
#text_object.size = params['text_size']
#text_object.space_character = params['width']
# Get font object
font = None
if params['fontname'] != 'Bfont':
# Add font so it's available to Blender
font = load_font(params['fontname'])
else:
# Get default font
font = bpy.data.fonts['Bfont']
# set the font
#text_object.font = font
# function call createSoftText(title,extrude,bevel_depth,spacemode,textsize,width,font,cylinder)
createSoftText(params['title'],params['extrude'],params['bevel_depth'],params['spacemode'],params['text_size'],params['width'], font, params['cylinder_on_off'])
# Change the material settings (color, alpha, etc...)
#material_object = bpy.data.materials['Material.001']
material_object = bpy.data.materials['MAT_PRE_Obsidian'] #match the text material in Blend file
material_object.diffuse_color = params['diffuse_color']
material_object.specular_color = params['specular_color']
material_object.specular_intensity = params['specular_intensity']
material_object.alpha = params['alpha']
# Set the render options. It is important that these are set
# to the same values as the current OpenShot project. These
# params are automatically set by OpenShot
bpy.context.scene.render.filepath = params['output_path']
bpy.context.scene.render.fps = params['fps']
try:
bpy.context.scene.render.file_format = params['file_format']
bpy.context.scene.render.color_mode = params['color_mode']
except:
bpy.context.scene.render.image_settings.file_format = params['file_format']
bpy.context.scene.render.image_settings.color_mode = params['color_mode']
bpy.data.worlds[0].horizon_color = params['horizon_color']
bpy.context.scene.render.resolution_x = params['resolution_x']
bpy.context.scene.render.resolution_y = params['resolution_y']
bpy.context.scene.render.resolution_percentage = params['resolution_percentage']
bpy.context.scene.frame_start = params['start_frame']
bpy.context.scene.frame_end = params['end_frame']
# Animation Speed (use Blender's time remapping to slow or speed up animation)
animation_speed = int(params['animation_speed']) # time remapping multiplier
new_length = int(params['end_frame']) * animation_speed # new length (in frames)
bpy.context.scene.frame_end = new_length
bpy.context.scene.render.frame_map_old = 1
bpy.context.scene.render.frame_map_new = animation_speed
if params['start_frame'] params['end_frame']:
bpy.context.scene.frame_start = params['end_frame']
bpy.context.scene.frame_end = params['end_frame']
# Render the current animation to the params['output_path'] folder
bpy.ops.render.render(animation=params['animation'])

And now the result in Openshot :


Educational videos are a great teaching tool, so I have been learning how to create them by using FOSS. Unfortunately, I have not found a free software that has everything you need to create a quality educational video. Probably, even commercial programs have their own limitations and several programs are always needed.

Nice features in OpenShot

In this post I want to comment why I think that OpenShot is a very interesting software that you should try for preparing your educational videos.

After some tests in Ubuntu 15.10 and the recommended software versions. I must admit that OpenShot seems to lack stability and crashes too often when performing quite simple tasks. For plain video editing I prefer the Kdenlive stability. However, I think that OpenShot is much more intuitive and has some interesting features related to effects and animations.

OpenShot is a free, simple-to-use, feature-rich video editor for Linux, Windows and Mac. Of course, it has many good things, but I’m very impressed with the amazing Animated Title Editor. You can read this post about it.

Openshot Blender Not Working

This feature is presented as easy-to-use templates that execute python scripts in Blender, so there is no need to learn Blender to include some nice animations in your educational videos.

A problem with customization

In the above mentioned post, it seems that in these animated titles have full alpha (i.e. transparency), and can be composited on top of any other video, such as the screenshot above of the chimpanzee. However, it appears to be a problem with this, and I was not able to do so.

I have found info on this bug here and here. There is a workaround for achieving transparent background on your animated titles. It implies that you have to edit those python scripts that execute Blender.

As explained in those links, you have to edit the phython-script files in /usr/share/pyshared/openshot/blender/scripts/

Openshot Blender No Frame Was Found

In each script search for

and add this line

Then search for

and add these lines

Already edited scripts

In the above mentioned link, mEon shared all the modified scripts in a dropbox public link. That link is still active, but I want to collaborate to the diffusion of these scripts by sharing an additional link:

Opportunities

All those animated titles are very nice, but I wonder how can I create more customized animations with a little python scripting. Take a look at the Blender Wiki example on using python scripts.

Openshot Blender Path

I’m sure that I can found many other scripts somewhere in the Internet. I will keep you informed ;)