Advertisement
Guest User

Blender Export Camera to Maya (.ma) script

a guest
Feb 17th, 2015
879
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.31 KB | None | 0 0
  1. #!BPY
  2.  
  3. # """
  4. # Name: 'Camera Tracking (.ma)'
  5. # Blender: 273
  6. # Group: 'Export'
  7. # Tip: 'Export camera tracking to Maya Ascii (for Shake, After Effects etc)'
  8. # """
  9.  
  10. import bpy
  11. import time
  12. import math
  13.  
  14. #
  15. # This operator exports the data from the active camera to a Maya ASCII .ma file.
  16. # The resulting file can be used in a variety of software programs, including
  17. # Autodesk Maya, Nothing Real/Apple Shake, Adobe After Effects and others.
  18. #
  19. # For Maya, you would think you could use FBX, but the camera is rotated the
  20. # wrong way in Maya 2010. In Modo, it is also upside down. So until Blender's FBX
  21. # export gets fixed, this is probably the only way to get correct matchmove
  22. # data out of Blender.
  23. #
  24. # This is based on a script found on videocopilot.net, updated for Blender's new
  25. # Python API, including support for menu integration.
  26. #
  27. # Author of the updated version: Peter Werner (peterwerner@gmx.ch).
  28. # This is provided as-is to the community, with no support given.
  29. #
  30. # The following bugs from the original script have been fixed:
  31. #
  32. #   - The number of keyframes is now written correctly (used to be hard-coded at 3),
  33. #     which caused Maya to complain on import
  34. #   - Now accounting for different coordinate axes and rotation behavior
  35. #     between Blender and Maya
  36. #
  37. # Current limitations:
  38. #
  39. #   - Currently, there is no UI to select which camera to export
  40. #     (or to export all of them)
  41. #   - Apparently the resolution settings don't end up
  42. #   - Playback range/FPS is not set (I thinks there is a playbackOptions MEl command)
  43. #   - Maya gives an error that the .dar attribute does not exist.
  44. #     This code is from the original script, so one would have to investigate this more
  45. #   - When opening the file in Maya, the camera does not appear to be in the correct
  46. #     position. You need to change the current frame for it to update.
  47. #   - If you did matchmoving (camera tracking), you may have to bake/apply the constraint,
  48. #     not sure since my computer is too slow for extensive testing with matchmoving.
  49. #
  50. class ExportCameraToMayaOperator( bpy.types.Operator ):
  51.  
  52.     bl_idname = "export.camera_to_maya"
  53.     bl_label  = "Export Camera to Maya"
  54.     filepath  = bpy.props.StringProperty( subtype="FILE_PATH" )
  55.  
  56.     @classmethod
  57.     def poll( cls, context ):
  58.        
  59.         # We need a camera in the active scene
  60.         return context.scene.camera != None
  61.    
  62.    
  63.     def execute( self, context ):
  64.        
  65.         self.exportTracking( context, self.filepath )
  66.         return { 'FINISHED' }
  67.  
  68.  
  69.     def invoke( self, context, event ):
  70.        
  71.         context.window_manager.fileselect_add( self )
  72.         return { 'RUNNING_MODAL' }
  73.  
  74.  
  75.     def exportTracking( self, context, mafilename ):
  76.  
  77.         t = {}
  78.        
  79.         t[ 'header' ] = []
  80.         t[ 'header' ].append( '//Maya ASCII scene\n//Name: camera.ma\n//Last modified: %s\n' % time.strftime( '%X %d/%m/%y' ) )
  81.         t[ 'header' ].append( 'currentUnit -l centimeter -a degree -t film;\n' )
  82.        
  83.         # Save current frame so we can restore it later
  84.         frameOriginal = context.scene.frame_current
  85.    
  86.         camObj = context.scene.camera
  87.         camera = bpy.data.cameras[ bpy.context.scene.camera.name ]
  88.    
  89.         matrix = camObj.matrix_world
  90.        
  91.         t[ 'header' ].append( 'createNode transform -n "%s";\n' % camera.name )
  92.         t[ 'header' ].append( '\tsetAttr ".t" -type "double3" 0 0 0 ;\n' )
  93.         t[ 'header' ].append( '\tsetAttr -av ".tx";\n' )
  94.         t[ 'header' ].append( '\tsetAttr -av ".ty";\n' )
  95.         t[ 'header' ].append( '\tsetAttr -av ".tz";\n' )
  96.         t[ 'header' ].append( '\tsetAttr ".r" -type "double3" 0 0 0 ;\n' )
  97.         t[ 'header' ].append( '\tsetAttr -av ".rx";\n' )
  98.         t[ 'header' ].append( '\tsetAttr -av ".ry";\n' )
  99.         t[ 'header' ].append( 'createNode camera -n "camera" -p "%s";\n' % camera.name )
  100.         t[ 'header' ].append( '\tsetAttr -k off ".v";\n' )
  101.         t[ 'header' ].append( '\tsetAttr ".rnd" no;\n' )
  102.        
  103.         yRes = context.scene.render.resolution_y
  104.         xRes = context.scene.render.resolution_x
  105.         aspX = context.scene.render.pixel_aspect_x
  106.         aspY = context.scene.render.pixel_aspect_y
  107.        
  108.         aspect = xRes * aspX / float( yRes * aspY )
  109.        
  110.         # if aspect > 1: x is constant, otherwise y constant
  111.         # constant comes from fov equations: fov = 2 * atan(aspect * 16.0 / camera.lens), aperturey = tan(fov/2)*camera.lens*2/25.4
  112.         # tracking seems to work better using 1.25, change as needed
  113.         #c = 16.0*2/25.4
  114.         c = 1.25
  115.         aperturex = min( c, c * aspect )
  116.         aperturey = min( c, c / aspect )
  117.        
  118.         t[ 'header' ].append( '\tsetAttr ".cap" -type "double2" %s %s ;\n' % (aperturex,aperturey) )
  119.         t[ 'header' ].append( '\tsetAttr ".dar" %s;\n' % aspect )
  120.        
  121.         t[ 'header' ].append( '\tsetAttr ".lsr" 1;\n' ) # lens squeeze ratio
  122.         t[ 'header' ].append( '\tsetAttr ".ff" 0;\n' )
  123.         t[ 'header' ].append( '\tsetAttr ".fl" %s;\n' % camera.lens ) # focal length
  124.         t[ 'header' ].append( '\tsetAttr ".ncp" 0.01;\n' )
  125.         t[ 'header' ].append( '\tsetAttr ".ow" 30;\n' )
  126.         t[ 'header' ].append( '\tsetAttr ".imn" -type "string" "camera1";\n' )
  127.         t[ 'header' ].append( '\tsetAttr ".den" -type "string" "camera1_depth";\n ')
  128.         t[ 'header' ].append( '\tsetAttr ".man" -type "string" "camera1_mask";\n' )
  129.        
  130.         startFrame = context.scene.frame_start
  131.         endFrame   = context.scene.frame_end
  132.         numFrames  = endFrame + 1 - startFrame
  133.        
  134.         for p in [ 'translateX', 'translateY', 'translateZ', 'rotateX', 'rotateY', 'rotateZ' ]:
  135.             t[ p ] = []
  136.             t[ p ].append( 'createNode animCurveTL -n "%s_%s";\n' % ( camObj.name, p ) )
  137.             t[ p ].append( '\tsetAttr ".tan" 10;\n' )
  138.             t[ p ].append( '\tsetAttr ".wgt" no;\n' )
  139.             # Fixed bug in the original script here -- this would always write out [0:3] instead of
  140.             # the actual number of frames, causing Maya to report a file read error to the user
  141.             t[ p ].append( '\tsetAttr -s 4 ".ktv[0:%s]" ' % ( numFrames - 1 ) )
  142.    
  143.         context.window_manager.progress_begin( startFrame, endFrame + 1 )
  144.        
  145.         for frame in range( startFrame, endFrame + 1 ):
  146.            
  147.             # Don't use "context.scene.frame_current = frame" here.
  148.             # It works in the interactive python shell, but the animation
  149.             # is not exported properly.
  150.             context.scene.frame_set( frame )
  151.  
  152.             context.window_manager.progress_update( frame )
  153.            
  154.             translation = matrix.translation
  155.             rotation    = matrix.to_euler()
  156.            
  157.             # Append transformations, taking Maya's different coordinate axis
  158.             # orientation into account.
  159.             # In Maya the positive y-axis is vertical up, in Blender positive y
  160.             # moves into the screen. In Maya, negative z goes into the screen.
  161.            
  162.             t[ 'translateX' ].append( '%s %s ' % ( frame,   translation.x ) )
  163.             t[ 'translateY' ].append( '%s %s ' % ( frame,   translation.z ) )
  164.             t[ 'translateZ' ].append( '%s %s ' % ( frame, - translation.y ) )
  165.            
  166.             # A 0 rotation camera in Blender looks down, one in Maya looks
  167.             # into the screen. In Blender, this means the camera points towards
  168.             # negative Z, in Maya towards negative Y.
  169.             # This means we need to rotate the Maya camera by -90 degrees in X
  170.             # (pi/2 in radians) so that an untransformed camera will end up
  171.             # oriented correctly.
  172.            
  173.             t[ 'rotateX' ].append( '%s %s ' % ( frame,   rotation.x  - math.pi / 2 ) )
  174.             t[ 'rotateY' ].append( '%s %s ' % ( frame,   rotation.z ) )
  175.             t[ 'rotateZ' ].append( '%s %s ' % ( frame, - rotation.y ) )
  176.        
  177.         # Restore the current frame to the original value
  178.         context.scene.frame_current = frameOriginal
  179.        
  180.         context.window_manager.progress_end()
  181.        
  182.         t[ 'footer' ] = []
  183.         t[ 'footer' ].append( 'connectAttr "%s_translateX.o" "%s.tx";\n' % ( camObj.name, camObj.name ) )
  184.         t[ 'footer' ].append( 'connectAttr "%s_translateY.o" "%s.ty";\n' % ( camObj.name, camObj.name ) )
  185.         t[ 'footer' ].append( 'connectAttr "%s_translateZ.o" "%s.tz";\n' % ( camObj.name, camObj.name ) )
  186.         t[ 'footer' ].append( 'connectAttr "%s_rotateX.o" "%s.rx";\n'    % ( camObj.name, camObj.name ) )
  187.         t[ 'footer' ].append( 'connectAttr "%s_rotateY.o" "%s.ry";\n'    % ( camObj.name, camObj.name ) )
  188.         t[ 'footer' ].append( 'connectAttr "%s_rotateZ.o" "%s.rz";\n'    % ( camObj.name, camObj.name ) )
  189.         t[ 'footer' ].append( 'connectAttr "%s_scaleX.o" "%s.sx";\n'     % ( camObj.name, camObj.name ) )
  190.         t[ 'footer' ].append( 'connectAttr "%s_scaleY.o" "%s.sy";\n'     % ( camObj.name, camObj.name ) )
  191.         t[ 'footer' ].append( 'connectAttr "%s_scaleZ.o" "%s.sz";\n'     % ( camObj.name, camObj.name ) )
  192.        
  193.         t[ 'footer' ].append( '\n// End of camera.ma\n' )
  194.  
  195.        
  196.         if not mafilename.endswith( '.ma' ):
  197.             mafilename += '.ma'
  198.        
  199.         mafile = open( mafilename, 'w' )
  200.        
  201.         for line in t[ 'header' ]:
  202.             mafile.write(line)
  203.  
  204.         for p in [ 'translateX', 'translateY', 'translateZ', 'rotateX', 'rotateY', 'rotateZ' ]:
  205.             for line in t[ p ]:
  206.                 mafile.write( line )
  207.             mafile.write( ';\n' )
  208.  
  209.         for line in t[ 'footer' ]:
  210.             mafile.write( line )
  211.  
  212.  
  213. def menu_func( self, context ):
  214.     self.layout.operator_context = 'INVOKE_DEFAULT'
  215.     self.layout.operator( ExportCameraToMayaOperator.bl_idname, text="Camera to Maya (.ma)" )
  216.  
  217. def register():
  218.     bpy.utils.register_class( ExportCameraToMayaOperator )
  219.     # Append a menu item for our operator item to the file menu
  220.     bpy.types.INFO_MT_file_export.append( menu_func )
  221.  
  222. def unregister():
  223.     bpy.utils.unregister_class( ExportCameraToMayaOperator )
  224.  
  225. # Register the operator if the script is running directly (i.e. not
  226. # being imported as a module)
  227. if __name__ == "__main__":
  228.     register()
  229.  
  230.     # Call our new operator when executing the script (use while debugging)
  231.     #bpy.ops.export.camera_to_maya( 'INVOKE_DEFAULT' )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement