예제 #1
0
파일: mesh.py 프로젝트: tscrypter/mixer
def encode_baked_mesh(obj):
    """
    Bake an object as a triangle mesh and encode it.
    """
    stats_timer = share_data.current_stats_timer

    # Bake modifiers
    depsgraph = bpy.context.evaluated_depsgraph_get()
    obj = obj.evaluated_get(depsgraph)

    stats_timer.checkpoint("eval_depsgraph")

    # Triangulate mesh (before calculating normals)
    mesh = obj.data if obj.type == "MESH" else obj.to_mesh()
    if mesh is None:
        # This happens for empty curves
        return bytes()

    bm = bmesh.new()
    bm.from_mesh(mesh)
    bmesh.ops.triangulate(bm, faces=bm.faces)
    bm.to_mesh(mesh)
    bm.free()

    stats_timer.checkpoint("triangulate_mesh")

    # Calculate normals, necessary if auto-smooth option enabled
    mesh.calc_normals()
    mesh.calc_normals_split()
    # calc_loop_triangles resets normals so... don't use it

    stats_timer.checkpoint("calc_normals")

    # get active uv layer
    uvlayer = mesh.uv_layers.active

    vertices = []
    normals = []
    uvs = []
    indices = []
    material_indices = []  # array of triangle index, material index

    current_material_index = -1
    current_face_index = 0
    logger.debug("Writing %d polygons", len(mesh.polygons))
    for f in mesh.polygons:
        for loop_id in f.loop_indices:
            index = mesh.loops[loop_id].vertex_index
            vertices.extend(mesh.vertices[index].co)
            normals.extend(mesh.loops[loop_id].normal)
            if uvlayer:
                uvs.extend([x for x in uvlayer.data[loop_id].uv])
            indices.append(loop_id)

        if f.material_index != current_material_index:
            current_material_index = f.material_index
            material_indices.append(current_face_index)
            material_indices.append(current_material_index)
        current_face_index = current_face_index + 1

    if obj.type != "MESH":
        obj.to_mesh_clear()

    stats_timer.checkpoint("make_buffers")

    # Vericex count + binary vertices buffer
    size = len(vertices) // 3
    binary_vertices_buffer = common.int_to_bytes(size, 4) + struct.pack(
        f"{len(vertices)}f", *vertices)

    stats_timer.checkpoint("write_verts")

    # Normals count + binary normals buffer
    size = len(normals) // 3
    binary_normals_buffer = common.int_to_bytes(size, 4) + struct.pack(
        f"{len(normals)}f", *normals)

    stats_timer.checkpoint("write_normals")

    # UVs count + binary uvs buffer
    size = len(uvs) // 2
    binary_uvs_buffer = common.int_to_bytes(size, 4) + struct.pack(
        f"{len(uvs)}f", *uvs)

    stats_timer.checkpoint("write_uvs")

    # material indices + binary material indices buffer
    size = len(material_indices) // 2
    binary_material_indices_buffer = common.int_to_bytes(
        size, 4) + struct.pack(f"{len(material_indices)}I", *material_indices)

    stats_timer.checkpoint("write_material_indices")

    # triangle indices count + binary triangle indices buffer
    size = len(indices) // 3
    binary_indices_buffer = common.int_to_bytes(size, 4) + struct.pack(
        f"{len(indices)}I", *indices)

    stats_timer.checkpoint("write_tri_idx_buff")

    return (binary_vertices_buffer + binary_normals_buffer +
            binary_uvs_buffer + binary_material_indices_buffer +
            binary_indices_buffer)
예제 #2
0
파일: mesh.py 프로젝트: tscrypter/mixer
def encode_base_mesh_geometry(mesh_data):
    stats_timer = share_data.current_stats_timer

    # We do not synchronize "select" and "hide" state of mesh elements
    # because we consider them user specific.

    bm = bmesh.new()
    bm.from_mesh(mesh_data)

    stats_timer.checkpoint("bmesh_from_mesh")

    binary_buffer = bytes()

    logger.debug("Writing %d vertices", len(bm.verts))
    bm.verts.ensure_lookup_table()

    verts_array = []
    for vert in bm.verts:
        verts_array.extend((*vert.co, ))

    stats_timer.checkpoint("make_verts_buffer")

    binary_buffer += struct.pack(f"1I{len(verts_array)}f", len(bm.verts),
                                 *verts_array)

    stats_timer.checkpoint("encode_verts_buffer")

    # Vertex layers
    # Ignored layers for now:
    # - skin (BMVertSkin)
    # - deform (BMDeformVert)
    # - paint_mask (float)
    # Other ignored layers:
    # - shape: shape keys are handled with Shape Keys at the mesh and object level
    # - float, int, string: don't really know their role
    binary_buffer += encode_bmesh_layer(bm.verts.layers.bevel_weight, bm.verts,
                                        extract_layer_float)

    stats_timer.checkpoint("verts_layers")

    logger.debug("Writing %d edges", len(bm.edges))
    bm.edges.ensure_lookup_table()

    edges_array = []
    for edge in bm.edges:
        edges_array.extend(
            (edge.verts[0].index, edge.verts[1].index, edge.smooth, edge.seam))

    stats_timer.checkpoint("make_edges_buffer")

    binary_buffer += struct.pack(f"1I{len(edges_array)}I", len(bm.edges),
                                 *edges_array)

    stats_timer.checkpoint("encode_edges_buffer")

    # Edge layers
    # Ignored layers for now: None
    # Other ignored layers:
    # - freestyle: of type NotImplementedType, maybe reserved for future dev
    # - float, int, string: don't really know their role
    binary_buffer += encode_bmesh_layer(bm.edges.layers.bevel_weight, bm.edges,
                                        extract_layer_float)
    binary_buffer += encode_bmesh_layer(bm.edges.layers.crease, bm.edges,
                                        extract_layer_float)

    stats_timer.checkpoint("edges_layers")

    logger.debug("Writing %d faces", len(bm.faces))
    bm.faces.ensure_lookup_table()

    faces_array = []
    for face in bm.faces:
        faces_array.extend((face.material_index, face.smooth, len(face.verts)))
        faces_array.extend((vert.index for vert in face.verts))

    stats_timer.checkpoint("make_faces_buffer")

    binary_buffer += struct.pack(f"1I{len(faces_array)}I", len(bm.faces),
                                 *faces_array)

    stats_timer.checkpoint("encode_faces_buffer")

    # Face layers
    # Ignored layers for now: None
    # Other ignored layers:
    # - freestyle: of type NotImplementedType, maybe reserved for future dev
    # - float, int, string: don't really know their role
    binary_buffer += encode_bmesh_layer(bm.faces.layers.face_map, bm.faces,
                                        extract_layer_int)

    stats_timer.checkpoint("faces_layers")

    # Loops layers
    # A loop is an edge attached to a face (so each edge of a manifold can have 2 loops at most).
    # Ignored layers for now: None
    # Other ignored layers:
    # - float, int, string: don't really know their role
    binary_buffer += encode_bmesh_layer(bm.loops.layers.uv, loops_iterator(bm),
                                        extract_layer_uv)
    binary_buffer += encode_bmesh_layer(bm.loops.layers.color,
                                        loops_iterator(bm),
                                        extract_layer_color)

    stats_timer.checkpoint("loops_layers")

    bm.free()

    return binary_buffer
예제 #3
0
def encode_baked_mesh(obj):
    """
    Bake an object as a triangle mesh and encode it.
    """
    stats_timer = share_data.current_stats_timer

    # Bake modifiers
    depsgraph = bpy.context.evaluated_depsgraph_get()
    obj = obj.evaluated_get(depsgraph)

    stats_timer.checkpoint("eval_depsgraph")

    # Triangulate mesh (before calculating normals)
    mesh = obj.data if obj.type == "MESH" else obj.to_mesh()
    if mesh is None:
        # This happens for empty curves
        return bytes()

    original_bm = None
    if obj.type == "MESH":
        # Mesh is restored later only if is has not been generated from a curve or something else
        original_bm = bmesh.new()
        original_bm.from_mesh(mesh)

    bm = bmesh.new()
    bm.from_mesh(mesh)
    bmesh.ops.triangulate(bm, faces=bm.faces)
    bm.to_mesh(mesh)
    bm.free()

    stats_timer.checkpoint("triangulate_mesh")

    # Calculate normals, necessary if auto-smooth option enabled
    mesh.calc_normals()
    mesh.calc_normals_split()
    # calc_loop_triangles resets normals so... don't use it

    stats_timer.checkpoint("calc_normals")

    # get active uv layer
    uvlayer = mesh.uv_layers.active

    vertices = array.array("d", (0.0, )) * len(mesh.vertices) * 3
    mesh.vertices.foreach_get("co", vertices)

    normals = array.array("d", (0.0, )) * len(mesh.loops) * 3
    mesh.loops.foreach_get("normal", normals)

    if uvlayer:
        uvs = array.array("d", (0.0, )) * len(mesh.loops) * 2
        mesh.uv_layers[0].data.foreach_get("uv", uvs)
    else:
        uvs = []

    indices = array.array("i", (0, )) * len(mesh.loops)
    mesh.loops.foreach_get("vertex_index", indices)

    if len(obj.material_slots) <= 1:
        material_indices = []
    else:
        material_indices = array.array("i", (0, )) * len(mesh.polygons)
        mesh.polygons.foreach_get("material_index", material_indices)

    if obj.type != "MESH":
        obj.to_mesh_clear()
    else:
        original_bm.to_mesh(mesh)
        original_bm.free()

    stats_timer.checkpoint("make_buffers")

    # Vericex count + binary vertices buffer
    size = len(vertices) // 3
    binary_vertices_buffer = common.int_to_bytes(size, 4) + struct.pack(
        f"{len(vertices)}f", *vertices)

    stats_timer.checkpoint("write_verts")

    # Normals count + binary normals buffer
    size = len(normals) // 3
    binary_normals_buffer = common.int_to_bytes(size, 4) + struct.pack(
        f"{len(normals)}f", *normals)

    stats_timer.checkpoint("write_normals")

    # UVs count + binary uvs buffer
    size = len(uvs) // 2
    binary_uvs_buffer = common.int_to_bytes(size, 4) + struct.pack(
        f"{len(uvs)}f", *uvs)

    stats_timer.checkpoint("write_uvs")

    # material indices + binary material indices buffer
    size = len(material_indices)
    binary_material_indices_buffer = common.int_to_bytes(
        size, 4) + struct.pack(f"{len(material_indices)}I", *material_indices)

    stats_timer.checkpoint("write_material_indices")

    # triangle indices count + binary triangle indices buffer
    size = len(indices) // 3
    binary_indices_buffer = common.int_to_bytes(size, 4) + struct.pack(
        f"{len(indices)}I", *indices)

    stats_timer.checkpoint("write_tri_idx_buff")

    return (binary_vertices_buffer + binary_normals_buffer +
            binary_uvs_buffer + binary_material_indices_buffer +
            binary_indices_buffer)