Ejemplo n.º 1
0
def wireframe(
        obj: bpy.types.Object,
        evaluated: bool) -> typing.List[typing.Tuple[float, float, float]]:
    '''
    Get coords of verts for edges of an object.

    Args:
        obj: An object that can be converted to mesh.
        evaluated: Whether to apply modifiers.

    Returns:
        points: A list of coordinates.
    '''

    points = []

    if evaluated:
        deps = bpy.context.view_layer.depsgraph
        obj = obj.evaluated_get(deps)

    mesh = obj.to_mesh()
    bm = bmesh.new()

    bm.from_mesh(mesh)
    bm.transform(obj.matrix_world)

    for edge in bm.edges:
        for vert in edge.verts:
            points.append(vert.co.xyz)

    bm.free()
    obj.to_mesh_clear()

    return points
Ejemplo n.º 2
0
def bake_frame(ob: bpy.types.Object, frame: int, export_obj=None):
    scene = bpy.context.scene

    shape_name = 'cache__F{:04d}'.format(frame)
    data_path = 'key_blocks["{}"].value'.format(shape_name)

    ## clean out the old keys
    if ob.data.shape_keys.animation_data and ob.data.shape_keys.animation_data.action:
        action = ob.data.shape_keys.animation_data.action
        for curve in action.fcurves:
            if curve.data_path == data_path:
                action.fcurves.remove(curve)
                break

    scene.frame_set(frame)

    mesh = ob.to_mesh(scene, apply_modifiers=True, settings="RENDER")
    shape = add_shape_key(ob, shape_name)

    for index in range(len(ob.data.vertices)):
        shape.data[index].co = mesh.vertices[index].co

    ## this keys them on for the duration of the animation
    shape.value = 0.0
    ob.data.shape_keys.keyframe_insert(data_path, frame=frame - 1)
    shape.value = 1.0
    ob.data.shape_keys.keyframe_insert(data_path, frame=frame)
    shape.value = 0.0
    ob.data.shape_keys.keyframe_insert(data_path, frame=frame + 1)

    if export_obj:
        ## the blender OBJ importer adjusts for Y up in other packages
        ## so rotate the mesh here before export
        rotate_mat = mathutils.Matrix.Rotation(-math.pi / 2, 4, 'X')
        mesh.transform(rotate_mat)

        ## man the OBJ format is simple. No wonder people love it.
        print('+ Exporting frame {} to "{}"'.format(frame, export_obj))
        with open(export_obj, 'w') as fp:
            for v in mesh.vertices:
                fp.write('v {:6f} {:6f} {:6f}\n'.format(
                    v.co[0], v.co[1], v.co[2]))

            ## smoothing
            # fp.write( 's 1\n' )

            for f in mesh.polygons:
                msg = "f"
                for v in f.vertices:
                    msg += ' {:d}'.format(v + 1)
                msg += '\n'
                fp.write(msg)

            ## one extra line at the end
            fp.write('\n')

    bpy.data.meshes.remove(mesh)
Ejemplo n.º 3
0
def temporary_mesh_object(source : bpy.types.Object) -> bpy.types.Object:
    """Creates a temporary mesh object from a nonmesh object that will only exist for the duration
       of the context."""
    assert source.type != "MESH"

    obj = bpy.data.objects.new(source.name, source.to_mesh(bpy.context.scene, True, "RENDER"))
    obj.draw_type = "WIRE"
    obj.matrix_basis, obj.matrix_world = source.matrix_basis, source.matrix_world
    obj.parent = source.parent

    bpy.context.scene.objects.link(obj)
    try:
        yield obj
    finally:
        bpy.data.objects.remove(obj)
Ejemplo n.º 4
0
def sync(rpr_context, obj: bpy.types.Object, **kwargs):
    """ Converts object into blender's mesh and exports it as mesh """

    try:
        # This operation adds new mesh into bpy.data.meshes, that's why it should be removed after usage.
        # obj.to_mesh() could also return None for META objects.
        new_mesh = obj.to_mesh()
        log("sync", obj, new_mesh)

        if new_mesh:
            mesh.sync(rpr_context, obj, mesh=new_mesh, **kwargs)
            return True

        return False

    finally:
        # it's important to clear created mesh
        obj.to_mesh_clear()
Ejemplo n.º 5
0
def normalize_skinning_weights(obj: bpy.types.Object) -> bpy.types.Mesh:
    bpy.context.view_layer.objects.active = obj
    bpy.ops.object.mode_set(mode="EDIT")
    bpy.ops.mesh.select_mode(type="VERT")
    bpy.ops.mesh.select_all(action="DESELECT")

    bm = bmesh.from_edit_mesh(obj.data)
    bm.verts.ensure_lookup_table()
    for idx in range(len(bm.verts)):
        bm.select_history.add(bm.verts[idx])
        bpy.ops.object.vertex_weight_normalize_active_vertex()
        bpy.ops.mesh.select_all(action="DESELECT")

    mesh = obj.to_mesh()
    bm.to_mesh(mesh)
    bm.free()
    bpy.ops.object.mode_set(mode="OBJECT")
    return mesh
Ejemplo n.º 6
0
def adjust_shape_key(obj: bpy.types.Object,
                     name: str,
                     blend_weight: float,
                     vertices: np.ndarray = None):
    bpy.context.view_layer.objects.active = obj
    key_block = bpy.data.shape_keys["Key"].key_blocks[name]
    key_block.value = blend_weight
    if vertices is not None:
        bpy.ops.object.mode_set(mode="EDIT")
        bm = bmesh.from_edit_mesh(obj.data)
        bm.verts.ensure_lookup_table()
        for idx in range(len(bm.verts)):
            bm.verts[idx].co = (vertices[idx][0], vertices[idx][1],
                                vertices[idx][2])
        mesh = obj.to_mesh()
        bm.to_mesh(mesh)
        bm.free()
        bpy.ops.object.mode_set(mode="OBJECT")
def _get_camera_space_bounding_box(context: bpy.types.Context,
                                   camera_obj: bpy.types.Object,
                                   target_obj: bpy.types.Object) -> Bounds2D:
    # TODO support more than just meshes (esp. metaballs)
    if target_obj.type != 'MESH':
        raise Exception(f"Target object {target_obj} is not a mesh")

    # Get latest version of target object with modifiers such as armature applied
    depsgraph = context.evaluated_depsgraph_get()
    target_obj = target_obj.evaluated_get(depsgraph)

    m_obj_to_world = target_obj.matrix_world
    m_world_to_cam = camera_obj.rotation_euler.to_matrix().inverted()

    obj_verts = target_obj.to_mesh().vertices
    cam_verts = [m_world_to_cam @ (m_obj_to_world @ v.co) for v in obj_verts]

    return Bounds2D.from_points(cam_verts)
Ejemplo n.º 8
0
def obj2np(obj: bpy.types.Object, dtype: type = np.float32, apply_modifier: bool = False,
           frame: int = bpy.context.scene.frame_current, geo_type: str = "position",
           is_local: bool = False, as_homogeneous: bool = False, mode: str = "dynamic") -> np.ndarray:
    # Input: obj(bpy.types.Object), Output: positions or normals
    bpy.context.scene.frame_set(frame)
    if type(obj.data) == bpy.types.Mesh :
        if apply_modifier:
            depsgraph = bpy.context.evaluated_depsgraph_get()
            obj = obj.evaluated_get(depsgraph)
            mesh = obj.to_mesh()
            return np.array([vec2np(v.co) for v in mesh.vertices], dtype=dtype)
        world_matrix = world_matrix2np(obj, dtype=dtype)  # (4, 4)
        return mesh2np(obj.data, world_matrix=world_matrix, geo_type=geo_type, dtype=dtype,
                       is_local=is_local, frame=frame, as_homogeneous=as_homogeneous)
    elif type(obj.data) == bpy.types.Armature:
        return armature2np(obj.data, dtype=dtype, mode=mode, frame=frame)
    else:
        raise NotImplementedError(
            f"{type(obj.data)} is not supported with obj2np")
def cache_blur_data(rpr_context, obj: bpy.types.Object):
    if obj.rpr.deformation_blur and isinstance(rpr_context, RPRContext2):
        try:
            # This operation adds new mesh into bpy.data.meshes, that's why it should be removed
            # after usage. obj.to_mesh() could also return None for META objects.
            new_mesh = obj.to_mesh()
            log("sync", obj, new_mesh)

            if new_mesh:
                mesh.cache_blur_data(rpr_context, obj, new_mesh)
                return True

            return False

        finally:
            # it's important to clear created mesh
            obj.to_mesh_clear()

    else:
        mesh.cache_blur_data(rpr_context, obj)
Ejemplo n.º 10
0
 def __init__(self,
              obj: bpy.types.Object,
              depsgraph: bpy.types.Depsgraph,
              ARMATURE=False,
              ANIMATION=False
              ):
     """Constructor that pulls geometry data from bpy"""
     
     # ## ORIG CONSTRUCTOR ##
     
     self.vertexlist = list()
     self.submesh_list = list()
     self.submesh_material = ""
     
     self.vertexcount = 0
     
     self.attr_dict = dict()
     
     self.attr_dict["binormals"] = True
     self.attr_dict["colours_diffuse"] = False
     self.attr_dict["normals"] = True
     self.attr_dict["positions"] = True
     self.attr_dict["tangent_dimensions"] = 3
     self.attr_dict["tangents"] = True
     self.attr_dict["texture_coords"] = 1
     
     # ## END ##
     
     self.name = obj.data.name
     # obj to mesh
     # to_mesh(depsgraph, apply_modifiers, calc_undeformed=False) -> Mesh
     bpymesh = obj.to_mesh(depsgraph, True)
     
     # collect mesh vertices to ogre_types.Vertex
     # triangulate
     self.bmesh_triangulate(bpymesh)
     # update normals, tangents, bitangents
     bpymesh.calc_tangents()
     
     bpy_uvdata = bpymesh.uv_layers.active.data
     
     if bpymesh.vertex_colors.active is not None:
         bpy_color = bpymesh.vertex_colors.active.data
     else:
         bpy_color = None
     
     # Loop through the tris in the triangulated mesh
     for poly in bpymesh.polygons:
         # confirm that what we have is a tri.
         self.is_valid_tri(poly)
         # for tri reference
         tri = list()
         # for every vertex, create an ogre Vertex!
         for index in range(3):
             # get the index of the vertex and the loop
             vert_ref = poly.vertices[index]
             loop_ref = poly.loop_indices[index]
             
             # get the vertex coords, normals, tangent and bitangent
             vc = cc(bpymesh.vertices[vert_ref].co)
             vn = cc(bpymesh.vertices[vert_ref].normal)
             vt = cc(bpymesh.loops[loop_ref].tangent)
             # TODO: confirm this works as binormal
             vb = cc(bpymesh.loops[vert_ref].bitangent)
             
             uv = bpy_uvdata[loop_ref].uv
             
             if bpy_color:
                 rgb = bpy_color[loop_ref].color
                 rgba = [rgb[0], rgb[1], rgb[2], 1]
             else:
                 rgba = [1, 1, 1, 1]
             # TODO: better rgba
             
             # get the bone / vertexgroup influences
             # TODO: confirm this works
             bw = []
             if ARMATURE:
                 for group in bpymesh.vertices[vert_ref].groups:
                     if group.weight > 0.01:
                         vg = obj.vertex_groups[group.group]
                         bw[vg.name] = group.weight
             
             # create vertex
             vert = Vertex(vc, vn, uv=uv, tangent=vt, binormal=vb, rgba=rgba, boneweights=bw)
             
             # add the Vertex to our list in the Mesh, and to the tri
             tri.append(self.add_vertex(vert))
         
         # for every poly (tri) add a tri to our submesh list
         self.add_sm_tri(tri)
     
     # we go back to our object
     
     # and get that material!
     self.pull_sm_material(obj)
     
     if ANIMATION:
         # TODO: export poses
         # ... and anims
         pass
Ejemplo n.º 11
0
def sync(obj_prim,
         obj: bpy.types.Object,
         mesh: bpy.types.Mesh = None,
         **kwargs):
    """ Creates pyrpr.Shape from obj.data:bpy.types.Mesh """
    from .object import sdf_name

    if not mesh:
        mesh = obj.data

    log("sync", mesh, obj)

    data = MeshData.init_from_mesh(mesh, obj=obj)
    if not data:
        return

    stage = obj_prim.GetStage()

    usd_mesh = UsdGeom.Mesh.Define(
        stage,
        obj_prim.GetPath().AppendChild(Tf.MakeValidIdentifier(mesh.name)))

    usd_mesh.CreateDoubleSidedAttr(True)
    usd_mesh.CreateFaceVertexIndicesAttr(data.vertex_indices)
    usd_mesh.CreateFaceVertexCountsAttr(data.num_face_vertices)

    usd_mesh.CreateSubdivisionSchemeAttr(UsdGeom.Tokens.none)
    usd_mesh.SetNormalsInterpolation(UsdGeom.Tokens.faceVarying)

    points_attr = usd_mesh.CreatePointsAttr(data.vertices)
    normals_attr = usd_mesh.CreateNormalsAttr(data.normals)

    # here we can't just call mesh.calc_loop_triangles to update loops because Blender crashes
    armature = obj.find_armature()
    if armature and kwargs.get('is_use_animation', False):
        scene = kwargs.get('scene')

        frame_current = scene.frame_current

        frame_start = kwargs.get('frame_start') if kwargs.get(
            'is_restrict_frames') else scene.frame_start
        frame_end = kwargs.get('frame_end') if kwargs.get(
            'is_restrict_frames') else scene.frame_end

        for frame in range(frame_start, frame_end + 1):
            scene.frame_set(frame)
            new_mesh = obj.to_mesh()

            new_data = MeshData.init_from_mesh(new_mesh, obj=obj)

            points_attr.Set(new_data.vertices, frame)
            normals_attr.Set(new_data.normals, frame)

        obj.to_mesh_clear()

        scene.frame_set(frame_current)

    for name, uv_layer in data.uv_layers.items():
        uv_primvar = usd_mesh.CreatePrimvar(
            "st",  # default name, later we'll use sdf_path(name)
            Sdf.ValueTypeNames.TexCoord2fArray,
            UsdGeom.Tokens.faceVarying)
        uv_primvar.Set(uv_layer[0])
        uv_primvar.SetIndices(Vt.IntArray.FromNumpy(uv_layer[1]))

        break  # currently we use only first UV layer

    _assign_materials(obj_prim, obj.original, usd_mesh)