Source code for blenderproc.python.loader.ObjectLoader

"""Provides `load_obj`, which allows to load different 3D object files. """

import os
import re
from typing import List, Optional, Dict

import bpy

from blenderproc.python.types.MeshObjectUtility import MeshObject, convert_to_meshes
from blenderproc.python.utility.Utility import Utility
from blenderproc.python.material.MaterialLoaderUtility import create_material_from_texture
from blenderproc.python.material.MaterialLoaderUtility import create as create_material


[docs] def load_obj(filepath: str, cached_objects: Optional[Dict[str, List[MeshObject]]] = None, use_legacy_obj_import: bool = False, **kwargs) -> List[MeshObject]: """ Import all objects for the given file and returns the loaded objects In .obj files a list of objects can be saved in. In .ply files only one object can be saved so the list has always at most one element :param filepath: the filepath to the location where the data is stored :param cached_objects: a dict of filepath to objects, which have been loaded before, to avoid reloading (the dict is updated in this function) :param use_legacy_obj_import: If this is true the old legacy obj importer in python is used. It is slower, but it correctly imports the textures in the ShapeNet dataset. :param kwargs: all other params are handed directly to the bpy loading fct. check the corresponding documentation :return: The list of loaded mesh objects. """ if not os.path.exists(filepath): raise FileNotFoundError(f"The given filepath does not exist: {filepath}") if cached_objects is not None and isinstance(cached_objects, dict): if filepath in cached_objects.keys(): created_obj = [] for obj in cached_objects[filepath]: # duplicate the object created_obj.append(obj.duplicate()) return created_obj loaded_objects = load_obj(filepath, cached_objects=None, **kwargs) cached_objects[filepath] = loaded_objects return loaded_objects # save all selected objects previously_selected_objects = bpy.context.selected_objects if filepath.endswith(".obj"): # load an .obj file: if use_legacy_obj_import: bpy.ops.import_scene.obj(filepath=filepath, **kwargs) else: bpy.ops.wm.obj_import(filepath=filepath, **kwargs) elif filepath.endswith(".ply"): PLY_TEXTURE_FILE_COMMENT = "comment TextureFile " model_name = os.path.basename(filepath) # Read file with open(filepath, "r", encoding="latin-1") as file: ply_file_content = file.read() # Check if texture file is given if PLY_TEXTURE_FILE_COMMENT in ply_file_content: # Find name of texture file texture_file_name = re.search(f"{PLY_TEXTURE_FILE_COMMENT}(.*)\n", ply_file_content).group(1) # Determine full texture file path texture_file_path = os.path.join(os.path.dirname(filepath), texture_file_name) material = create_material_from_texture( texture_file_path, material_name=f"ply_{model_name}_texture_model" ) # Change content of ply file to work with blender ply importer new_ply_file_content = ply_file_content new_ply_file_content = new_ply_file_content.replace("property float texture_u", "property float s") new_ply_file_content = new_ply_file_content.replace("property float texture_v", "property float t") # Create temporary .ply file tmp_ply_file = os.path.join(Utility.get_temporary_directory(), model_name) with open(tmp_ply_file, "w", encoding="latin-1") as file: file.write(new_ply_file_content) # Load .ply mesh bpy.ops.import_mesh.ply(filepath=tmp_ply_file, **kwargs) else: # If no texture was given # load a .ply mesh bpy.ops.import_mesh.ply(filepath=filepath, **kwargs) # Create default material material = create_material('ply_material') material.map_vertex_color() selected_objects = [obj for obj in bpy.context.selected_objects if obj not in previously_selected_objects] for obj in selected_objects: obj.data.materials.append(material.blender_obj) elif filepath.endswith('.dae'): bpy.ops.wm.collada_import(filepath=filepath) elif filepath.lower().endswith('.stl'): # load a .stl file bpy.ops.wm.stl_import(filepath=filepath, **kwargs) # add a default material to stl file mat = bpy.data.materials.new(name="stl_material") mat.use_nodes = True selected_objects = [obj for obj in bpy.context.selected_objects if obj not in previously_selected_objects] for obj in selected_objects: obj.data.materials.append(mat) elif filepath.lower().endswith('.fbx'): bpy.ops.import_scene.fbx(filepath=filepath) elif filepath.lower().endswith('.glb') or filepath.lower().endswith('.gltf'): bpy.ops.import_scene.gltf(filepath=filepath) mesh_objects = convert_to_meshes([obj for obj in bpy.context.selected_objects if obj not in previously_selected_objects]) # Add model_path cp to all objects for obj in mesh_objects: obj.set_cp("model_path", filepath) return mesh_objects