-
-
Save JanHmmr/78eaf488a0e848b598daae94a96e0a7b to your computer and use it in GitHub Desktop.
Blender Remesh Function
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import subprocess | |
| def remesh(blender_path: str, # Path to blender executable | |
| model_path: str, # Path to input model | |
| export_path: str, # Path to output model | |
| faces: int, # Number of faces for remesh | |
| merge: bool = False, # Merge duplicate vertices before exporting | |
| preserve_uvs: bool = False | |
| ) -> None: | |
| """ | |
| Remesh a model using Blender and export it | |
| Parameters: | |
| blender_path (str): Path to blender executable | |
| model_path (str): Path to input model | |
| export_path (str): Path to output model | |
| faces (int): Number of faces for remesh | |
| merge (bool): Merge duplicate vertices before exporting | |
| Returns: | |
| None | |
| """ | |
| code = f""" | |
| # Import the module | |
| import bpy | |
| from pathlib import Path | |
| # Enable CUDA for better performance | |
| bpy.context.preferences.addons['cycles'].preferences.compute_device_type = 'CUDA' | |
| bpy.context.preferences.addons['cycles'].preferences.get_devices() | |
| # Set empty scene | |
| bpy.ops.wm.read_factory_settings(use_empty=True) | |
| # Delete all current meshes | |
| bpy.ops.object.select_all(action='DESELECT') | |
| bpy.ops.object.select_by_type(type='MESH') | |
| bpy.ops.object.delete() | |
| # Import the model | |
| export_path = r'{export_path}' | |
| import_path = r'{model_path}' | |
| if import_path.endswith('.glb'): | |
| bpy.ops.import_scene.gltf(filepath=import_path) | |
| elif import_path.endswith('.fbx'): | |
| bpy.ops.import_scene.fbx(filepath=import_path) | |
| if not bpy.context.object: | |
| bpy.context.view_layer.objects.active = bpy.data.objects[0] | |
| bpy.data.objects[0].select_set(True) | |
| else: | |
| print("Unsupported file format. Please use .glb or .fbx.") | |
| raise SystemExit | |
| if {preserve_uvs} and not export_path.endswith('.stl'): | |
| blend_path = Path(r'{export_path}').with_suffix("." + "blend") | |
| bpy.ops.wm.save_as_mainfile(filepath=str(blend_path)) | |
| # Select the imported model | |
| bpy.ops.object.select_all(action='SELECT') | |
| bpy.ops.object.shade_smooth_by_angle() | |
| obj = bpy.context.object | |
| if {preserve_uvs}: | |
| orignal_obj = obj.copy() | |
| orignal_obj.data = obj.data.copy() | |
| if {merge}: | |
| bpy.ops.object.mode_set(mode='EDIT') | |
| bpy.ops.mesh.select_all(action='SELECT') | |
| bpy.ops.mesh.remove_doubles() | |
| bpy.ops.object.mode_set(mode='OBJECT') | |
| # Remesh the model | |
| obj.data.remesh_mode = 'QUAD' | |
| bpy.ops.object.quadriflow_remesh( | |
| target_faces={faces}, | |
| use_mesh_symmetry=False, | |
| use_preserve_sharp=True, | |
| use_preserve_boundary=True | |
| ) | |
| if {preserve_uvs}: | |
| transfer_mod = obj.modifiers.new(name="DataTransferMod", type='DATA_TRANSFER') | |
| transfer_mod.object = orignal_obj | |
| transfer_mod.use_loop_data = True | |
| transfer_mod.data_types_loops = {{'UV'}} | |
| transfer_mod.loop_mapping = 'POLYINTERP_NEAREST' | |
| transfer_mod.use_object_transform = False | |
| bpy.ops.object.datalayout_transfer(modifier = transfer_mod.name) | |
| bpy.ops.object.modifier_apply(modifier=transfer_mod.name) | |
| bpy.ops.file.unpack_all(method = 'USE_LOCAL') | |
| # Merge vertices | |
| if {merge}: | |
| print("Merging") | |
| bpy.ops.object.mode_set(mode='EDIT') | |
| bpy.ops.mesh.select_all(action='SELECT') | |
| bpy.ops.mesh.remove_doubles() | |
| bpy.ops.object.mode_set(mode='OBJECT') | |
| # Export the model | |
| if export_path.endswith('.glb'): | |
| bpy.ops.export_scene.gltf(filepath=export_path) | |
| elif export_path.endswith('.fbx'): | |
| bpy.ops.export_scene.fbx(filepath=export_path) | |
| elif export_path.endswith('.obj'): | |
| bpy.ops.wm.obj_export(filepath=export_path) | |
| elif export_path.endswith('.stl'): | |
| bpy.ops.wm.stl_export(filepath=export_path) | |
| elif export_path.endswith('.usdc'): | |
| bpy.ops.wm.usd_export(filepath=export_path) | |
| else: | |
| print("Unsupported file format. Please use .glb, .fbx, .obj, .stl, or .usdc.") | |
| raise SystemExit | |
| if {preserve_uvs} and not export_path.endswith('.stl') and blend_path.exists(): | |
| blend_path.unlink() | |
| """ | |
| # Run the script using blender | |
| cmd = [blender_path, "-b", "--python-expr", code] | |
| result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
| # Print the output | |
| print(result.stdout.decode()) | |
| # Print any errors that occurred | |
| # print("Error:", result.stderr.decode()) | |
| if __name__ == "__main__": | |
| blender_path = r"C:\Program Files\Blender Foundation\Blender 4.1\blender.exe" | |
| model_path = r"C:\Users\janun\Documents\3DAI\Blender Remesh\test2.glb" | |
| export_path = r"C:\Users\janun\Documents\3DAI\Blender Remesh\test_remesh.obj" | |
| faces = 5000 | |
| merge = True | |
| preserve_uvs = True | |
| remesh(blender_path, model_path, export_path , faces , merge , preserve_uvs) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment