from math import radians import sys, platform, os, time, bpy, requests, json, bmesh, shutil from PIL import Image import platform # if platform.system() == 'Windows': # sys.path.append('e:\\libs\\') # else: # sys.path.append('/data/deploy/make3d/make2/libs/') sys.path.append('/home/acprint/code/libs/') import config, libs def bmesh_copy_from_object(obj, transform=True, triangulate=True, apply_modifiers=False): """Returns a transformed, triangulated copy of the mesh""" assert obj.type == 'MESH' if apply_modifiers and obj.modifiers: import bpy depsgraph = bpy.context.evaluated_depsgraph_get() obj_eval = obj.evaluated_get(depsgraph) me = obj_eval.to_mesh() bm = bmesh.new() bm.from_mesh(me) obj_eval.to_mesh_clear() else: me = obj.data if obj.mode == 'EDIT': bm_orig = bmesh.from_edit_mesh(me) bm = bm_orig.copy() else: bm = bmesh.new() bm.from_mesh(me) if transform: matrix = obj.matrix_world.copy() if not matrix.is_identity: bm.transform(matrix) matrix.translation.zero() if not matrix.is_identity: bm.normal_update() if triangulate: bmesh.ops.triangulate(bm, faces=bm.faces) return bm def fix_link_texture(pid): # 修改obj中的mtl文件为pid_original.mtl path = os.path.join(workdir, 'print', f'{pid}_{orderId}') filename = os.path.join(path, f'{pid}_original.obj') with open(filename, 'r') as f: lines = f.readlines() for i in range(len(lines)): if lines[i].startswith('mtllib'): lines[i] = f'mtllib {pid}_original.mtl\n' break with open(filename, 'w') as f: f.writelines(lines) f.close() # 将pid.mtl文件复制为pid_original.mtl _decimate shutil.copy(os.path.join(path, f'{pid}.mtl'), os.path.join(path, f'{pid}_original.mtl')) shutil.copy(os.path.join(path, f'{pid}Tex1.jpg'), os.path.join(path, f'{pid}Tex1_decimate.jpg')) texture_file = os.path.join(path, f'{pid}Tex1_decimate.jpg') if os.path.exists(texture_file): img = Image.open(texture_file) img = img.resize((int(img.size[0] * 0.5), int(img.size[1] * 0.5))) img.save(texture_file, quality=90, optimize=True) print('resize texture file to 50% success') # 修改pid_original.mtl文件中的贴图为pid_old.jpg with open(os.path.join(path, f'{pid}_original.mtl'), 'r') as f: lines = f.readlines() for i in range(len(lines)): if lines[i].startswith('map_Kd'): lines[i] = f'map_Kd {pid}Tex1_decimate.jpg\n' break with open(os.path.join(path, f'{pid}_original.mtl'), 'w') as f: f.writelines(lines) f.close() def main(): start = time.time() get_printsize_url = 'https://mp.api.suwa3d.com/api/printOrder/info' upload_obj_volume_url = 'https://mp.api.suwa3d.com/api/physical/add' # ?pid=1&order_id=1&faces=1&volume=1 res = requests.get(f'{get_printsize_url}?id={orderId}') print('获取打印尺寸:', res.text) if res.status_code == 200: pid = res.json()['data']['pid'] path = os.path.join(workdir, 'print', f'{pid}_{orderId}') filename = os.path.join(path, f'{pid}.obj') bpy.ops.object.delete(use_global=False, confirm=False) bpy.context.scene.unit_settings.scale_length = 0.001 bpy.context.scene.unit_settings.length_unit = 'CENTIMETERS' bpy.context.scene.unit_settings.mass_unit = 'GRAMS' print('正在处理:', filename) bpy.ops.import_scene.obj(filepath=filename) obj = bpy.context.selected_objects[0] print('原始模型尺寸:', obj.dimensions) bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) print('应用后模型尺寸:', obj.dimensions) shutil.copy(filename, os.path.join(path, f'{pid}_original.obj')) filename_original = os.path.join(path, f'{pid}_original.obj') for f in res.json()['data']['fileList']: if "undefined" in f: continue try: height = float(f.split('_')[-2][:-2]) * 10 except Exception as e: print("eeee",e) bpy.ops.wm.quit_blender() return obj = bpy.context.selected_objects[0] print(f'{f}处理前{height}mm模型尺寸: {obj.dimensions}') scale = height / obj.dimensions.z obj.scale = (scale, scale, scale) bpy.ops.object.transform_apply(scale=True) print(f'{f}处理后{height}mm模型尺寸: {obj.dimensions}') bpy.ops.export_scene.obj(filepath=os.path.join(path, f'{pid}.obj')) if os.path.exists(os.path.join(path, f)): os.remove(os.path.join(path, f)) os.rename(os.path.join(path, f'{pid}.obj'), os.path.join(path, f)) config.oss_bucket.put_object_from_file(f'objs/print/{pid}/{f}', os.path.join(path, f)) # 重新加载模型,然后生成数字模型 bpy.ops.object.delete(use_global=False, confirm=False) fix_link_texture(pid) bpy.ops.import_scene.obj(filepath=filename_original) bpy.context.scene.unit_settings.scale_length = 0.001 bpy.context.scene.unit_settings.length_unit = 'CENTIMETERS' bpy.context.scene.unit_settings.mass_unit = 'GRAMS' obj = bpy.context.selected_objects[0] bpy.context.view_layer.objects.active = obj obj.select_set(True) scale = 90 / obj.dimensions.y obj.scale = (scale, scale, scale) bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) # if str(pid) == '120745': bpy.ops.wm.save_as_mainfile(filepath=os.path.join(path, f'{pid}_{orderId}.blend')) headcount = res.json()['data']['headcount'] bm = bmesh_copy_from_object(obj) obj_volume = round(bm.calc_volume() / 1000, 3) print('volume:', obj_volume) print('weight:', obj_volume * 1.2, 'g') tempWeight = obj_volume * 1.2 faces = len(obj.data.polygons) print('faces:', faces) upload_res = requests.get(f'{upload_obj_volume_url}?pid={pid}&order_id={orderId}&faces={faces}&volume={obj_volume}&headcount={headcount}&weight={tempWeight}') print('上传模型体积:', upload_res.text) # 生成数字模型 faces_dest = 120000 * headcount # 减面 faces_current = len(obj.data.polygons) bpy.ops.object.modifier_add(type='DECIMATE') bpy.context.object.modifiers["Decimate"].ratio = faces_dest / faces_current bpy.ops.object.modifier_apply(modifier="Decimate") bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_VOLUME', center='MEDIAN') bpy.context.object.location[0] = 0 bpy.context.object.location[1] = 0 bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) bpy.ops.export_scene.obj(filepath=os.path.join(path, f'{pid}_decimate.obj')) bpy.ops.export_scene.gltf(filepath=os.path.join(path, f'{pid}_decimate.glb'), export_format='GLB', export_apply=True, export_jpeg_quality=95) config.oss_bucket.put_object_from_file(f'glbs/3d/{pid}.glb', os.path.join(path, f'{pid}_decimate.glb')) bpy.ops.wm.quit_blender() if __name__ == '__main__': if platform.system() == 'Windows': workdir = 'E:\\' else: workdir = '/data/datasets/' if len(sys.argv) - (sys.argv.index("--") + 1) < 1: print("Usage: blender -b -P resize_model.py -- ") sys.exit(1) orderId = sys.argv[sys.argv.index("--") + 1] main()