Add UI Animation Render addon

UI Animation Render allows you to capture the Blender UI for each frame of an animation.
This enables you to neatly show how the UI and different values are changing during animation.

More info, and demo here: https://gitlab.com/LucaRood/screenrender

Reviewed By: mont29

Differential Revision: https://developer.blender.org/D7180
This commit is contained in:
Luca Rood 2020-03-19 13:48:28 +01:00
parent e4ccb4cef4
commit 654afac96c
1 changed files with 223 additions and 0 deletions

View File

@ -0,0 +1,223 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
import bpy
bl_info = {
"name": "UI Animation Render",
"author": "Luca Rood",
"description": "Render animations of the Blender UI.",
"blender": (2, 80, 0),
"version": (0, 1, 0),
"location": "View3D > Sidebar > View Tab and Ctrl+Shift+F12",
"warning": "",
"category": "Render"
}
km = None
def draw_ui(prefs, layout):
layout.prop(prefs, "delay")
col = layout.column(align=True)
col.label(text="Animation Highlight:")
row = col.row()
row.prop(prefs, "anim_highlight", expand=True)
if prefs.anim_highlight == "replace":
split = col.split(factor=0.2)
split.label(text="Color")
row = split.row(align=True)
row.prop(prefs, "highlight_color", text="")
row.prop(prefs, "highlight_blend", text="Blend")
class UIAnimationRenderPreferences(bpy.types.AddonPreferences):
bl_idname = __name__
delay: bpy.props.FloatProperty(
name="Capture Delay",
description="How much time to wait (seconds) before capturing each frame, to allow the viewport to clean up",
default=0.5
)
anim_highlight: bpy.props.EnumProperty(
name="Animation Highlight",
description="What to do with the animated field highlight color",
items=[("keep", "Keep", "Keep the animated field highlight", 0),
("hide", "Hide", "Hide the animated field highlight", 1),
("replace", "Replace", "Replace the animated field highlight", 2)],
default="keep"
)
highlight_color: bpy.props.FloatVectorProperty(
name="Highlight Color",
description="Color to use for animated field highlights",
subtype='COLOR',
default=(1.0, 1.0, 1.0)
)
highlight_blend: bpy.props.FloatProperty(
name="Highlight Blend",
description="How much the highlight color influences the field color",
default=0.5
)
def draw(self, context):
draw_ui(self, self.layout)
class RenderScreen(bpy.types.Operator):
bl_idname = "render.render_screen"
bl_label = "Render Screen"
bl_description = "Capture the screen for each animation frame and write to the render output path"
_timer = None
_f_initial = 1
_theme_blend = 0.0
_theme_key = (0, 0, 0)
_theme_key_sel = (0, 0, 0)
_theme_anim = (0, 0, 0)
_theme_anim_sel = (0, 0, 0)
_theme_driven = (0, 0, 0)
_theme_driven_sel = (0, 0, 0)
def modal(self, context, event):
if event.type in {'RIGHTMOUSE', 'ESC'}:
self.stop(context)
return {'CANCELLED'}
if event.type == 'TIMER':
scene = context.scene
f_curr = scene.frame_current
bpy.ops.screen.screenshot(filepath=context.scene.render.frame_path(frame=f_curr))
if f_curr < scene.frame_end:
scene.frame_set(f_curr + 1)
else:
self.stop(context)
return {'FINISHED'}
return {'RUNNING_MODAL'}
def execute(self, context):
# Adjust animation highlight (theme)
prefs = context.preferences
addon_prefs = prefs.addons[__name__].preferences
theme = prefs.themes[0].user_interface.wcol_state
if addon_prefs.anim_highlight == "hide":
self._theme_blend = theme.blend
theme.blend = 0.0
elif addon_prefs.anim_highlight == "replace":
self._theme_blend = theme.blend
self._theme_key = theme.inner_key.copy()
self._theme_key_sel = theme.inner_key_sel.copy()
self._theme_anim = theme.inner_anim.copy()
self._theme_anim_sel = theme.inner_anim_sel.copy()
self._theme_driven = theme.inner_driven.copy()
self._theme_driven_sel = theme.inner_driven_sel.copy()
theme.blend = addon_prefs.highlight_blend
theme.inner_key = addon_prefs.highlight_color
theme.inner_key_sel = addon_prefs.highlight_color
theme.inner_anim = addon_prefs.highlight_color
theme.inner_anim_sel = addon_prefs.highlight_color
theme.inner_driven = addon_prefs.highlight_color
theme.inner_driven_sel = addon_prefs.highlight_color
# Set frame
scene = context.scene
self._f_initial = scene.frame_current
scene.frame_set(scene.frame_start)
# Start timer
wm = context.window_manager
self._timer = wm.event_timer_add(addon_prefs.delay, window=context.window)
wm.modal_handler_add(self)
return {'RUNNING_MODAL'}
def stop(self, context):
# Stop timer
wm = context.window_manager
wm.event_timer_remove(self._timer)
# Reset frame
context.scene.frame_set(self._f_initial)
# Reset theme
prefs = context.preferences
addon_prefs = prefs.addons[__name__].preferences
theme = prefs.themes[0].user_interface.wcol_state
if addon_prefs.anim_highlight == "hide":
theme.blend = self._theme_blend
elif addon_prefs.anim_highlight == "replace":
theme.blend = self._theme_blend
theme.inner_key = self._theme_key
theme.inner_key_sel = self._theme_key_sel
theme.inner_anim = self._theme_anim
theme.inner_anim_sel = self._theme_anim_sel
theme.inner_driven = self._theme_driven
theme.inner_driven_sel = self._theme_driven_sel
class VIEW3D_PT_ui_animation_render(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = "View"
bl_label = "UI Animation Render"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = False
prefs = context.preferences
addon_prefs = prefs.addons[__name__].preferences
layout.operator(RenderScreen.bl_idname)
draw_ui(addon_prefs, layout)
def register():
global km
bpy.utils.register_class(UIAnimationRenderPreferences)
bpy.utils.register_class(RenderScreen)
bpy.utils.register_class(VIEW3D_PT_ui_animation_render)
wm = bpy.context.window_manager
km = wm.keyconfigs.addon.keymaps.new(name='Screen', space_type='EMPTY')
km.keymap_items.new('render.render_screen', 'F12', 'PRESS', shift=True, ctrl=True)
def unregister():
global km
bpy.utils.unregister_class(UIAnimationRenderPreferences)
bpy.utils.unregister_class(RenderScreen)
bpy.utils.unregister_class(VIEW3D_PT_ui_animation_render)
if km is not None:
wm = bpy.context.window_manager
wm.keyconfigs.addon.keymaps.remove(km)
km = None