Beispiel #1
0
def set_bone_head_tail(armature_object_name, bone_name, head_location=None, tail_location=None):

    """ A CHILD is attached with its HEAD to the TAIL of the PARENT """

    logger.info('set_bone_head_tail: ...')

    # ===================
    # If head_location and tail_location is set to the same value, THE BONE DISAPPEARS
    # ===================
    assert not head_location == tail_location

    set_mode(
        active_object_name=armature_object_name,
        mode='EDIT',
        configure_scene_for_basic_ops=False)
    armature_object = bpy.data.objects[armature_object_name]

    if head_location is not None:
        logger.debug('head_location: ' + str(head_location))
        armature_object.data.edit_bones[bone_name].head = Vector(head_location)

    if tail_location is not None:
        logger.debug('tail_location: ' + str(tail_location))
        armature_object.data.edit_bones[bone_name].tail = Vector(tail_location)

    bpy.ops.object.mode_set(mode='OBJECT')
    logger.info('set_bone_head_tail: Done')
    def _count_missing_images(self, sorted_file_list):
        logger.debug('_count_missing_images: ...')
        number_missing_images = 0
        try:
            text_str, current_number_str = self.split_text_and_number_string(
                os.path.splitext(sorted_file_list[0])[0])
            last_number = int(current_number_str)

            for file_name in sorted_file_list[1:]:
                text_str, current_number_str = self.split_text_and_number_string(
                    os.path.splitext(file_name)[0])
                current_number = int(current_number_str)
                if current_number != last_number + 1:
                    current_missing_images = current_number - last_number - 1
                    logger.info('There are ' + str(current_missing_images) +
                                ' images missing between ' + str(last_number) +
                                ' and ' + str(current_number))
                    number_missing_images += current_missing_images
                last_number = current_number
            valid_count = True
        except ValueError:
            valid_count = False

        logger.debug('_count_missing_images: Done')
        return number_missing_images, valid_count
 def _collect_texture(type_to_texture_file_path, use_map_type, filepath):
     logger.debug('filepath: ' + filepath)
     if type_to_texture_file_path[use_map_type] is None:
         type_to_texture_file_path[use_map_type] = filepath
     else:
         logger.warning('Two Textures with the same use_type:')
         logger.warning('First: ' + use_map_type + ', ' +
                        type_to_texture_file_path[use_map_type])
         logger.warning('Second: ' + use_map_type + ', ' + filepath)
         logger.warning('We use the first texture as : ' + use_map_type)
Beispiel #4
0
    def apply_single_transformation_to_multiple_models(
            transformation_ifp,
            model_idp,
            transformed_model_odp,
            save_clouds=False,
            save_meshes=False,
            lazy=True,
            log_info_sub_methods=True):

        logger.info('apply_single_transformation_to_multiple_models: ...')
        if not (save_clouds ^ save_meshes):
            logger.debug('Either save_clouds or save_meshes must be True')
            assert False

        model_files = sorted([
            model_file for model_file in os.listdir(model_idp)
            if (os.path.isfile(os.path.join(model_idp, model_file))
                and os.path.splitext(model_file)[1] == '.ply')
        ])

        for model_file in sorted(model_files):

            output_path_to_transformed_model_file = os.path.join(
                transformed_model_odp, model_file)

            input_path_to_model_file = os.path.join(model_idp, model_file)

            TransformationTool.apply_single_transformation_to_single_model(
                ifp_model=input_path_to_model_file,
                ifp_transformation=transformation_ifp,
                ofp_model=output_path_to_transformed_model_file,
                save_point_clouds=save_clouds,
                save_meshes=save_meshes,
                lazy=lazy,
                log_info=log_info_sub_methods)

        logger.info('apply_single_transformation_to_multiple_models: Done')
Beispiel #5
0
    def apply_multiple_transformations_to_single_model(
            transformation_files_idp,
            model_ply_ifp,
            transformed_model_odp,
            suffix='',
            save_point_clouds=False,
            save_meshes=False,
            lazy=True,
            log_info_sub_methods=False):

        logger.info('apply_multiple_transformations_to_single_model: ...')

        if not (save_point_clouds ^ save_meshes):
            logger.debug('Either save_clouds or save_meshes must be True')
            assert False

        transformation_files = sorted([
            trans_file for trans_file in os.listdir(transformation_files_idp)
            if os.path.isfile(
                os.path.join(transformation_files_idp, trans_file))
        ])

        logger.vinfo('transformation_files_idp', transformation_files_idp)
        logger.vinfo('model_ply_ifp', model_ply_ifp)
        logger.vinfo('transformed_model_odp', transformed_model_odp)

        # Transform the point cloud and the mesh into
        # ground truth world coordinates and store it to disc afterwards
        # ==== Apply Transformation ====
        # Make sure .obj file was converted correctly
        assert os.path.isfile(model_ply_ifp)

        results = []
        with ProcessingPool() as pool:
            for transformation_file in sorted(
                    transformation_files):  # TODO FIXME
                logger.vinfo('transformation_file', transformation_file)

                transformed_model_ofp = os.path.join(
                    transformed_model_odp,
                    os.path.splitext(transformation_file)[0] + '_' + suffix +
                    os.path.splitext(model_ply_ifp)[1])

                logger.vinfo('transformed_model_ofp', transformed_model_ofp)

                input_path_to_transformation_file = os.path.join(
                    transformation_files_idp, transformation_file)
                assert os.path.isfile(input_path_to_transformation_file)

                result = pool.apipe(
                    TransformationTool.
                    apply_single_transformation_to_single_model, *[
                        model_ply_ifp, input_path_to_transformation_file,
                        transformed_model_ofp, save_point_clouds, save_meshes,
                        lazy, log_info_sub_methods
                    ])
                results.append(result)

            # Collect the asynchronous calls
            for result in results:
                result.get()

        logger.info('apply_multiple_transformations_to_single_model: Done')
    def create_material_nodes_for_cycle_using_blender_internal_textures(
            material_default_bsdf_type=DIFFUSE_BSDF,
            transparent_default_bsdf_type=TRANSPARENT_BSDF):
        """

        :param material_default_bsdf_type: DIFFUSE_BSDF or GLOSSY_BSDF
        :param transparent_default_bsdf_type: TRANSPARENT_BSDF or GLASS_BSDF
        :return:
        """

        logger.info(
            'create_material_nodes_for_cycle_using_blender_internal_textures: ...'
        )

        bpy.context.scene.render.engine = 'CYCLES'

        # # each object has several material slots, which link to the materials provided in bpy.data.materials
        # for material in bpy.data.materials:

        for object in bpy.data.objects:

            logger.debug('object.name: ' + object.name)

            for material_slot in object.material_slots:
                material = material_slot.material

                # https://wiki.blender.org/index.php/Dev:Py/Scripts/Cookbook/Code_snippets/Nodes
                logger.info('material.name: ' + material.name)

                # change only blender internal materials (keep cycle materials as is)
                if not material.use_nodes:

                    logger.debug('Adding nodes ...')

                    # this adds by default a node "Material Output" and a node "Diffuse BSDF"
                    material.use_nodes = True

                    # get the "Diffuse BSDF" node
                    nodes = material.node_tree.nodes
                    links = material.node_tree.links

                    # this diffuse node does automatically inherit the color of the material
                    shader_node_diffuse_bsdf = nodes.get(
                        NodeUtility.DIFFUSE_BSDF)
                    shader_node_material_output = nodes.get("Material Output")

                    # These texture file path should be valid
                    texture_type_to_file_path = NodeUtility._get_blender_internal_texture_type_to_file_paths(
                        material)

                    # 1 Case: Material is just a texture
                    #         Image Texture -> Diffuse BSDF/Glossy BSDF -> Material Output
                    color_texture_file_path = texture_type_to_file_path[
                        NodeUtility.USE_MAP_COLOR_DIFFUSE]
                    logger.debug('color_texture_file_path: ' +
                                 str(color_texture_file_path))

                    if color_texture_file_path is not None:

                        logger.debug('Converting Material With Texture: ' +
                                     color_texture_file_path)

                        logger.debug('Texture path is valid')

                        # test if the image texture node has already been created
                        shader_node_tex_image = nodes.get("Image Texture")
                        if not shader_node_tex_image:

                            shader_node_tex_image = nodes.new(
                                type='ShaderNodeTexImage')
                            shader_node_tex_image.image = bpy.data.images.load(
                                color_texture_file_path)

                            # link the nodes
                            links.new(shader_node_tex_image.outputs[0],
                                      shader_node_diffuse_bsdf.inputs[0])

                        # if material_default_bsdf_type == BICyclesMaterialConverter.GLOSSY_BSDF:
                        #
                        #     logger.debug('Replace Diffuse Material Node with Glossy Material Node' )
                        #     shader_node_glossy_bsdf = nodes.get(BICyclesMaterialConverter.GLOSSY_BSDF)
                        #     if not shader_node_glossy_bsdf:
                        #
                        #         shader_node_glossy_bsdf = nodes.new(type='ShaderNodeBsdfGlossy')
                        #
                        #         BICyclesMaterialConverter._replace_bsdf_node(material,
                        #                                                      old_node=shader_node_diffuse_bsdf,
                        #                                                      new_node=shader_node_glossy_bsdf,
                        #                                                      preceding_node=shader_node_tex_image,
                        #                                                      next_node=shader_node_material_output)

                    # 2 Case: Material is transparent
                    #         RGB -> Transparent BSDF/Glass BSDF -> Material Output
                    elif material.use_transparency:

                        logger.debug('Converting Transparent Material')

                        shader_node_transparent_or_glass_bsdf = nodes.get(
                            transparent_default_bsdf_type)
                        if not shader_node_transparent_or_glass_bsdf:

                            if transparent_default_bsdf_type == NodeUtility.GLASS_BSDF:
                                shader_node_transparent_or_glass_bsdf = nodes.new(
                                    type='ShaderNodeBsdfGlass')
                            else:
                                shader_node_transparent_or_glass_bsdf = nodes.new(
                                    type='ShaderNodeBsdfTransparent')

                            shader_node_RGB = nodes.new(type='ShaderNodeRGB')

                            NodeUtility.replace_bsdf_node_in_material(
                                material,
                                old_node=shader_node_diffuse_bsdf,
                                new_node=shader_node_transparent_or_glass_bsdf,
                                preceding_node=shader_node_RGB,
                                next_node=shader_node_material_output)

                    else:
                        logger.debug('Converting Material With Simple Color')
                        # by default there is just a diffuse bsdf created using the color of the material

                        if material_default_bsdf_type == NodeUtility.GLOSSY_BSDF:

                            logger.debug(
                                'Replace Diffuse Material Node with Glossy Material Node'
                            )
                            shader_node_glossy_bsdf = nodes.get(
                                NodeUtility.GLOSSY_BSDF)
                            if not shader_node_glossy_bsdf:
                                shader_node_glossy_bsdf = nodes.new(
                                    type='ShaderNodeBsdfGlossy')

                                NodeUtility.replace_bsdf_node_in_material(
                                    material,
                                    old_node=shader_node_diffuse_bsdf,
                                    new_node=shader_node_glossy_bsdf,
                                    preceding_node=None,
                                    next_node=shader_node_material_output)

                else:
                    logger.debug('Material has already a node ...')

        logger.info(
            'create_material_nodes_for_cycle_using_blender_internal_textures: Done'
        )
    def _get_blender_internal_texture_type_to_file_paths(material):

        some_other_name = material.name
        logger.debug(some_other_name)

        # fprint('material: ' + material.name)
        texture_name_set = set()
        texture_type_to_file_path = defaultdict(lambda: None)
        for texture_slot in material.texture_slots:

            if texture_slot:
                texture = texture_slot.texture

                texture_name_set.add(texture)
                # fprint('texture: ' + texture.name)
                if hasattr(texture, 'image'):
                    logger.debug('Material: ' + material.name + ', Texture: ' +
                                 texture.name)

                    logger.debug('use_map_color_diffuse: ' +
                                 str(texture_slot.use_map_color_diffuse))
                    logger.debug('use_map_normal: ' +
                                 str(texture_slot.use_map_normal))

                    # ==== Remark ====
                    # Relative paths start with '//' and are relative to the blend file.
                    # The prefix of paths to textures packed inside the .blend file are dependent on the original
                    # file path. For example <blend_file_folder>/textures/texture_file.ext, i.e. look like the
                    # following '//textures/<texturename>.<textureextension>'

                    if texture.image.packed_file is not None:
                        logger.debug('Image is packed')
                        # If the texture is packed, the file is definitively valid, otherwise check the file
                        image_is_valid = True
                    else:
                        logger.debug('Image is an external source')
                        image_is_valid = os.path.isfile(
                            bpy.path.abspath(texture.image.filepath))

                    if image_is_valid:
                        if texture_slot.use_map_color_diffuse:
                            NodeUtility._collect_texture(
                                texture_type_to_file_path,
                                NodeUtility.USE_MAP_COLOR_DIFFUSE,
                                texture.image.filepath)

                        elif texture_slot.use_map_normal:
                            NodeUtility._collect_texture(
                                texture_type_to_file_path,
                                NodeUtility.USE_MAP_NORMAL,
                                texture.image.filepath)

        logger.info('texture_type_to_file_path: ' +
                    str(texture_type_to_file_path))

        return texture_type_to_file_path