Advertisement
cjxd

view_interpolate.py

May 6th, 2017
327
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.15 KB | None | 0 0
  1. import bpy, bmesh
  2. import os
  3. import sys
  4. import numpy as np
  5.  
  6. from glob import glob
  7. from mathutils import Vector, Matrix
  8.  
  9. context = bpy.context
  10.  
  11. #
  12. # Camera settings
  13. #
  14. camera_size = Vector((1024, 1024))
  15. texture_size = Vector((1024, 1024))
  16. num_captures = 6
  17.  
  18. mid_cam_pos = Vector((-1, 0, 0.1))
  19. centre = Vector((0, 0, 0))
  20. max_angle = np.pi / 3
  21.  
  22. #
  23. # Mesh imperfection settings
  24. #
  25. mesh_simplify = 0.3
  26. mesh_confidence = 0.9
  27.  
  28. def look_at(pos, target):
  29.     '''
  30.     Utility function returning a rotation matrix.
  31.     Rotates an object at pos to look towards target.
  32.     '''
  33.     direction = target - pos
  34.     rot_quat = direction.to_track_quat('-Z', 'Y')
  35.    
  36.     return rot_quat.to_matrix().to_4x4()
  37.    
  38. def yaw_look_at(pos, target, yaw):
  39.     '''
  40.     Utility function returning a full transformation matrix.
  41.     Translates an object to pos, rotates to look towards target,
  42.     then applies a yaw rotation. A negative value of
  43.     yaw rotates left, and positive rotates right.
  44.     '''
  45.     local_rot = look_at(pos, target)
  46.     trans = Matrix.Translation(pos)
  47.     yaw = Matrix.Rotation(yaw, 4, Vector((0,0,1)))
  48.    
  49.     return yaw * trans * local_rot
  50.  
  51. def reset_scene():
  52.     '''
  53.     Utility function to remove all objects from the current scene.
  54.     '''
  55.     bpy.ops.wm.read_factory_settings()
  56.     #bpy.ops.wm.addon_enable(module="uv_perspective_project")
  57.  
  58.     for scene in bpy.data.scenes:
  59.         for obj in scene.objects:
  60.             scene.objects.unlink(obj)
  61.  
  62.     for bpy_data_iter in (
  63.             bpy.data.objects,
  64.             bpy.data.meshes,
  65.             bpy.data.lamps,
  66.             bpy.data.cameras,
  67.             bpy.data.materials,
  68.             bpy.data.images
  69.             ):
  70.         for id_data in bpy_data_iter:
  71.             bpy_data_iter.remove(id_data)
  72.            
  73. def setup_scene():
  74.     '''
  75.     "Lights, camera, ..."
  76.     '''
  77.     scene = context.scene
  78.    
  79.     # Lighting
  80.     scene.world.horizon_color = (1.0, 1.0, 1.0)
  81.     light_settings = scene.world.light_settings
  82.     light_settings.use_environment_light = True
  83.     light_settings.environment_energy = 1
  84.     light_settings.use_ambient_occlusion = True
  85.     light_settings.ao_factor = 0.1
  86.     light_settings.ao_blend_type = 'ADD'
  87.    
  88.     # Cameras
  89.     camera_data = bpy.data.cameras.new("Camera")
  90.     camera_data.type = 'PERSP'
  91.     camera_data.clip_start = 0.01
  92.     camera_data.clip_end = 10
  93.     camera_data.lens = 35
  94.     camera_data.lens_unit = 'MILLIMETERS'
  95.  
  96.     # Projection cameras
  97.     cam0 = bpy.data.objects.new("Cam0", camera_data)
  98.     cam0.matrix_world = yaw_look_at(mid_cam_pos, centre, -max_angle)
  99.     cam0["render_size"] = texture_size
  100.     scene.objects.link(cam0)
  101.     cam1 = bpy.data.objects.new("Cam1", camera_data)
  102.     cam1.matrix_world = yaw_look_at(mid_cam_pos, centre, max_angle)
  103.     cam1["render_size"] = texture_size
  104.     scene.objects.link(cam1)
  105.    
  106.     # Moveable intermediate camera
  107.     camC = bpy.data.objects.new("CamC", camera_data)
  108.     camC["render_size"] = camera_size
  109.     scene.objects.link(camC)
  110.    
  111.     scene.update()
  112.    
  113. def imperfect(object, origins = [Vector((0,0,0))]):
  114.     '''
  115.     Warps an object to emulate imperfections in depth estimation.
  116.     origins is a list of camera locations such that depth uncertainty
  117.     is added along the vector between object vertex and camera location.
  118.     '''
  119.     context.scene.objects.active = object
  120.    
  121.     # Apply decimate modifier
  122.     mod = object.modifiers.new("Simplify", 'DECIMATE')
  123.     mod.decimate_type = 'DISSOLVE'
  124.     mod.angle_limit = np.pi * mesh_simplify
  125.     bpy.ops.object.modifier_apply(apply_as='DATA', modifier=mod.name)
  126.    
  127.     bpy.ops.object.mode_set(mode='EDIT')
  128.     me = object.data
  129.     bm = bmesh.from_edit_mesh(me)
  130.    
  131.     # Deform vertices along camera orientations
  132.     q = (1 - mesh_confidence) / 50
  133.     if q > 0:
  134.         for v in bm.verts:
  135.             # Warp the mesh along one choice of vector
  136.             # by a gaussian with q factor derived from 1 - confidence
  137.             vector = origins[np.random.choice(2)] - v.co
  138.             vector.normalize()
  139.             v.co += vector * np.random.normal(0, q)
  140.        
  141.     bmesh.update_edit_mesh(me)
  142.     bpy.ops.object.mode_set(mode='OBJECT')
  143.  
  144. def project(images, object):
  145.     '''
  146.     Re-texturizes an object with projected textures
  147.     Requires the separate UV Perspective Project addon
  148.     '''
  149.     scene = context.scene
  150.     object.data.materials.clear()
  151.  
  152.     uvp = scene.uvPerspectiveProject
  153.     uvp.cameras_settings.clear()
  154.     uvp.object_name = object.name
  155.    
  156.     for i, image in enumerate(images):
  157.         # UV setup
  158.         uv = object.data.uv_textures.new("Proj" + str(i))
  159.    
  160.         # Texture setup
  161.         tex = bpy.data.textures.new("Tex" + str(i), type='IMAGE')
  162.         tex.image = image
  163.    
  164.         # Material setup
  165.         mat = bpy.data.materials.new("Mat" + str(i))
  166.         mat.use_shadeless = True
  167.         mtex = mat.texture_slots.add()
  168.         mtex.texture = tex
  169.         mtex.texture_coords = 'UV'
  170.         mtex.uv_layer = "Proj" + str(i)
  171.         object.data.materials.append(mat)
  172.  
  173.         # UV Perspective Project addon
  174.         uvp.cameras_settings.add()
  175.         uvp.cameras_settings[-1].camera_name = "Cam" + str(i)
  176.         uvp.cameras_settings[-1].uv_map_name = uv.name
  177.         uvp.cameras_settings[-1].material_slot_name = mat.name
  178.    
  179.     bpy.ops.object.uvperspectiveprojectoperator('EXEC_DEFAULT')
  180.  
  181. def render(camera, filepath, id=""):
  182.     '''
  183.     Renders the scene from a camera.
  184.     '''
  185.     if id == "":
  186.         id = camera.name
  187.        
  188.     context.scene.camera = camera                              
  189.     print("Rendering from %s" % (id))
  190.    
  191.     context.scene.render.image_settings.file_format = 'PNG'
  192.     context.scene.render.image_settings.color_mode = 'RGB'
  193.    
  194.     context.scene.render.filepath = "%s_%s.png" % (filepath, id)
  195.     context.scene.render.resolution_x = camera["render_size"][0]
  196.     context.scene.render.resolution_y = camera["render_size"][1]
  197.     context.scene.render.resolution_percentage = 100
  198.     bpy.ops.render.render(write_still=True)
  199.    
  200. def render_lerp(filepath):
  201.     '''
  202.     Renders all camera locations between Cam0 and Cam1
  203.     '''
  204.     lerp_camera = context.scene.objects["CamC"]
  205.     for i, lerp in enumerate(np.linspace(-max_angle, max_angle, num=num_captures)):
  206.         lerp_camera.matrix_world = yaw_look_at(mid_cam_pos, centre, lerp)
  207.         render(lerp_camera, filepath, i / (num_captures - 1))
  208.  
  209. def capture(model):
  210.     reset_scene()
  211.        
  212.     # Find first .obj file
  213.     obj_files = [y for x in os.walk(model) for y in glob(os.path.join(x[0], '*.obj'))]
  214.     filepath_src = obj_files[0]
  215.     filepath_dst = os.path.join(model, "renders")
  216.     if not os.path.exists(filepath_dst):
  217.         os.makedirs(filepath_dst)
  218.        
  219.     # Paths for pre-projection and post-projection
  220.     filepath_pre = os.path.join(filepath_dst, "view")
  221.     filepath_post = os.path.join(filepath_dst, "proj")
  222.  
  223.     print("Importing %s" % (filepath_src))
  224.     bpy.ops.import_scene.obj(filepath=filepath_src, use_split_objects=False, use_split_groups=False)
  225.     object = context.scene.objects[-1]
  226.    
  227.     setup_scene()
  228.     cam0 = context.scene.objects["Cam0"]
  229.     cam1 = context.scene.objects["Cam1"]
  230.    
  231.     # Pre-projection
  232.     render(cam0, filepath_pre)
  233.     render(cam1, filepath_pre)
  234.     render_lerp(filepath_pre)
  235.    
  236.     # Projection
  237.     images = []
  238.     images.append(bpy.data.images.load(filepath_pre + "_Cam0.png"))
  239.     images.append(bpy.data.images.load(filepath_pre + "_Cam1.png"))
  240.     imperfect(object, [cam0.location, cam1.location])
  241.     #project(images, object)
  242.    
  243.     # Post-projection
  244.     render_lerp(filepath_post)
  245.    
  246.     # Optional: save .blend file
  247.     #bpy.ops.wm.save_as_mainfile(filepath=filepath_dst + ".blend", check_existing=False)
  248.    
  249. def run(files):
  250.     for model in files:
  251.         capture(model)
  252.  
  253. if __name__ == "__main__":
  254.     argv = sys.argv
  255.     argv = argv[argv.index("--") + 1:]  # get all args after "--"
  256.     run(argv)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement