From 997375493fe0842967aa199263c8ff7b9917c0fa Mon Sep 17 00:00:00 2001 From: Mark Hale Date: Tue, 7 Mar 2017 23:04:09 +0000 Subject: [PATCH] VR videos. Signed-off-by: Mark Hale Former-commit-id: 7e14c54ae7696ac75aa54201674b6fa5c8a0801c --- contrib/blender/README.md | 17 +++++++++++++ contrib/blender/odm_video.py | 46 +++++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/contrib/blender/README.md b/contrib/blender/README.md index 6c92f74f..74b93008 100644 --- a/contrib/blender/README.md +++ b/contrib/blender/README.md @@ -22,3 +22,20 @@ To generate a 360 3D panoramic photo: Output is `/odm_photo/odm_photo_vr_L.jpg` and `/odm_photo/odm_photo_vr_R.jpg`. **NB: argument order matters!** + +# odm_video +Renders videos from ODM generated texture models. +Currently can produce 360 panoramic videos. +NB: the default resolution is 4096x2048 (maximum supported by Facebook). + +## Requirements +* Blender +* Python 2.7 (must be on your PATH) +* Spatial Media Metadata Injector (https://github.com/google/spatial-media/tree/master/spatialmedia) (place in `spatialmedia` subdirectory) + +## Usage +To generate a 360 panoramic photo: + + blender -b photo_360.blend --python odm_video.py -- + +Output is `/odm_video/odm_video_360.mp4`. diff --git a/contrib/blender/odm_video.py b/contrib/blender/odm_video.py index 47469f51..6faf8b15 100644 --- a/contrib/blender/odm_video.py +++ b/contrib/blender/odm_video.py @@ -5,8 +5,9 @@ # blender -b photo_360.blend --python odm_video.py -- import sys -import bpy import subprocess +import os +import bpy from common import loadMesh @@ -30,6 +31,7 @@ def main(): # create path thru waypoints curve = bpy.data.curves.new(name='CameraPath', type='CURVE') curve.dimensions = '3D' + curve.twist_mode = 'Z_UP' nurbs = curve.splines.new('NURBS') nurbs.points.add(numWaypoints-1) weight = 1 @@ -52,18 +54,37 @@ def main(): followPath.use_curve_follow = True animateContext = bpy.context.copy() animateContext['constraint'] = followPath - bpy.ops.constraint.followpath_path_animate(animateContext, constraint='CameraFollowPath') + bpy.ops.constraint.followpath_path_animate(animateContext, + constraint='CameraFollowPath', + frame_start=0, + length=numFrames) blendName = bpy.path.display_name_from_filepath(bpy.data.filepath) fileName = projectHome + '/odm_video/odm_' + blendName.replace('photo', 'video') scene.frame_start = 0 - scene.frame_end = numFrames - 1 + scene.frame_end = numFrames render = scene.render - render.filepath = fileName + render.filepath = fileName + '.mp4' + render.image_settings.file_format = 'FFMPEG' + if(render.use_multiview): + render.image_settings.stereo_3d_format.display_mode = 'TOPBOTTOM' + render.image_settings.views_format = 'STEREO_3D' + render.views[0].file_suffix = '' + format3d = 'top-bottom' + else: + width = render.resolution_x + height = render.resolution_y + format3d = 'none' render.resolution_x = 4096 render.resolution_y = 2048 - render.image_settings.file_format = 'FFMPEG' - #bpy.ops.render.render(animation=True) + + render.ffmpeg.audio_codec = 'AAC' + render.ffmpeg.codec = 'H264' + render.ffmpeg.format = 'MPEG4' + render.ffmpeg.video_bitrate = 45000 + bpy.ops.render.render(animation=True) + + writeMetadata(fileName+'.mp4', format3d) def loadWaypoints(filename): @@ -75,5 +96,18 @@ def loadWaypoints(filename): return waypoints +def writeMetadata(filename, format3d): + subprocess.run(['python', + 'spatialmedia', + '-i', + '--stereo='+format3d, + filename, + filename+'.injected']) + # check metadata injector was succesful + if os.path.exists(filename+'.injected'): + os.remove(filename) + os.rename(filename+'.injected', filename) + + if __name__ == '__main__': main()