Advertisement
Guest User

Untitled

a guest
May 29th, 2020
228
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.43 KB | None | 0 0
  1. import bpy
  2. import sys
  3. import numpy as np
  4. from mathutils import Vector
  5. DEG_TO_RAD = np.pi / 180.
  6.  
  7.  
  8. def _to_rad(data):
  9.     return (DEG_TO_RAD * data[0], DEG_TO_RAD * data[1], DEG_TO_RAD * data[2])
  10.  
  11.  
  12. def setup_scene():
  13.     for block in bpy.data.meshes:
  14.         if block.users == 0:
  15.             bpy.data.meshes.remove(block)
  16.     bpy.ops.object.mode_set(mode='OBJECT')
  17.     bpy.ops.object.select_all(action='SELECT')
  18.     bpy.ops.object.delete()
  19.     bpy.context.scene.render.resolution_x = 720
  20.     bpy.context.scene.render.resolution_y = 480
  21.     bpy.context.scene.frame_start = 0
  22.     bpy.context.scene.render.image_settings.color_mode = 'RGB'
  23.     bpy.context.scene.render.image_settings.file_format = 'PNG'
  24.  
  25.  
  26. def add_camera_light():
  27.     bpy.ops.object.camera_add(
  28.         location=(0.0, -3.5, 2.2),
  29.         rotation=_to_rad((60.8, 0.0, 0.0)),
  30.     )
  31.     bpy.context.scene.camera = bpy.context.object
  32.     bpy.ops.object.light_add(
  33.         type='SUN',
  34.         radius=1,
  35.         location=(33.2, -23.6, 17.4),
  36.         rotation=_to_rad((208, 140, 181)),
  37.     )
  38.     bpy.data.worlds["World"].node_tree.nodes["Background"].inputs[0].default_value = (1, 1, 1, 1)
  39.  
  40.  
  41. def make_plane():
  42.     """Underlying plane. Use collision so that it can support cloth on top."""
  43.     bpy.ops.mesh.primitive_plane_add(location=(0, 0, 0))
  44.     bpy.ops.transform.resize(value=(6.0, 6.0, 6.0))
  45.     bpy.ops.object.modifier_add(type='COLLISION')
  46.  
  47.  
  48. def make_cloth():
  49.     """Make a plane at height 0.2m (it then settles on the plane) and sub-divide."""
  50.     bpy.ops.mesh.primitive_plane_add(location=(0, 0, 0.2))
  51.     bpy.ops.object.editmode_toggle()
  52.     bpy.ops.mesh.subdivide(number_cuts=20)
  53.     bpy.ops.object.editmode_toggle()
  54.     bpy.ops.object.modifier_add(type='CLOTH')
  55.  
  56.     # Colors
  57.     mat = bpy.data.materials.new(name="CustomColor")
  58.     mat.use_nodes = False
  59.     mat.diffuse_color = (0,1,0,0)
  60.     bpy.context.object.data.materials.append(mat)
  61.  
  62.     return bpy.context.object
  63.  
  64.  
  65. def reset(cloth):
  66.     """
  67.    Remove vertex groups. The second for loop over actions removes keyframes,
  68.    which seems to avoid keyframes spilling over from prior actions.
  69.    """
  70.     for key in cloth.vertex_groups.keys():
  71.         cloth.vertex_groups.remove(cloth.vertex_groups[key])
  72.     cloth.modifiers["Cloth"].settings.vertex_group_mass = ''
  73.     for a in bpy.data.actions:
  74.         bpy.data.actions.remove(a)
  75.  
  76.  
  77. def define_action(cloth, vertex_idxs, frames_per_act):
  78.     """Define an action: pick up cloth at these vertex indices. Uses keyframing.
  79.  
  80.    We add an armature and make it the parent of a pinned vertex group. Parent set:
  81.    https://docs.blender.org/api/current/bpy.ops.object.html#bpy.ops.object.parent_set
  82.    """
  83.     if len(vertex_idxs) == 0:
  84.         print('A no-op action, just letting the scene settle.')
  85.         return
  86.     bpy.ops.object.armature_add(enter_editmode=False, location=(0, 0, 0))
  87.  
  88.     # Select the cloth _in_addition_ to the armature. The active one is the parent.
  89.     arm = bpy.context.object
  90.     cloth.select_set(True)
  91.     bpy.context.view_layer.objects.active = arm
  92.     bpy.ops.object.parent_set(type='ARMATURE_NAME')
  93.  
  94.     # Set cloth as the active object, and pin the designated vertices.
  95.     bpy.ops.object.select_all(action='DESELECT')
  96.     bpy.context.view_layer.objects.active = cloth
  97.     gripped_group = bpy.context.object.vertex_groups.new(name='Pinned')
  98.     gripped_group.add(vertex_idxs, 1.0, 'ADD')
  99.     cloth.modifiers["Cloth"].settings.vertex_group_mass = 'Pinned'
  100.  
  101.     # The arm modifier must be at the TOP of the modifier stack (over cloth)!
  102.     for _ in range(5):
  103.         bpy.ops.object.modifier_move_up(modifier="Armature")
  104.  
  105.     # Also need pinned set for the armature. The arm's default name is 'Bone'.
  106.     b_group = bpy.context.object.vertex_groups["Bone"]
  107.     b_group.add(vertex_idxs, 1.0, 'ADD')
  108.  
  109.     # Now animate by assigning the arm to different positions at certain keyframes.
  110.     bpy.context.view_layer.objects.active = arm
  111.     bpy.ops.object.posemode_toggle()
  112.     start_frame = bpy.context.scene.frame_current
  113.     frames = [start_frame + 1, start_frame + frames_per_act]
  114.     print('\nkeyframing at: {}'.format(frames))
  115.  
  116.     # Keyframe inserts need to use `b.[...]` attributes, like `b.location`.
  117.     for b in arm.pose.bones:
  118.         b.keyframe_insert("location", frame=frames[0])
  119.     c = arm.pose.bones["Bone"]
  120.  
  121.     # Create keyframe to move armatures upwards by 0.3m, and also moves cloth.
  122.     c.location += Vector((0, 0.3, 0))
  123.     for b in arm.pose.bones:
  124.         b.keyframe_insert("location", frame=frames[1])
  125.     bpy.ops.object.posemode_toggle()
  126.  
  127.  
  128. def advance_simulator(t, frames_per_act):
  129.     """Actually take steps in the physics simulator based on current keyframes.
  130.  
  131.    Whereas `define_action` method above defines the keyframes for the action,
  132.    this explicitly take steps in the physics simulator by setting the frames.
  133.    Images are saved AFTER we set the frame, with time and frame indices.
  134.    """
  135.     scene = bpy.context.scene
  136.     start = scene.frame_current + 1  # we already set at this frame earlier
  137.     print('Now stepping, going from {} to {}'.format(start, start + frames_per_act))
  138.     filename = 'images/act_{}_img_%06d.png'.format(str(t).zfill(2))
  139.     for f in range(start, start + frames_per_act):
  140.         scene.frame_set(f)  # Advance the simulated physics!
  141.         scene.render.filepath = filename % f
  142.         bpy.ops.render.render(write_still=True)
  143.  
  144.         # ---- debugging position AFTER setting frame ---- #
  145.         depsgraph = bpy.context.evaluated_depsgraph_get()
  146.         cloth_upd = cloth.evaluated_get(depsgraph)
  147.         v_c  = [cloth.matrix_world @ v.co for v in list(cloth.data.vertices)]
  148.         v_cd = [cloth_upd.matrix_world @ v.co for v in list(cloth_upd.data.vertices)]
  149.         print('after frame {}, vertex idx 0: {}, {}'.format(f, v_c[0], v_cd[0]))
  150.  
  151.  
  152. if __name__ == '__main__':
  153.     setup_scene()
  154.     add_camera_light()
  155.     make_plane()
  156.     cloth = make_cloth()
  157.     frames_per_act = 50
  158.     bpy.context.scene.frame_set(0)
  159.  
  160.     # First action: no-op (lets the scene settle). Equivalent to no items in list.
  161.     t = 0
  162.     vertex_idxs = []
  163.     reset(cloth)
  164.     define_action(cloth, vertex_idxs, frames_per_act)
  165.     advance_simulator(t, frames_per_act)
  166.  
  167.     # Second action: grasp at corner and pull upwards. TODO: physics issue??
  168.     t = 1
  169.     vertex_idxs = [0]
  170.     reset(cloth)
  171.     define_action(cloth, vertex_idxs, frames_per_act)
  172.     advance_simulator(t, frames_per_act)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement