You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

223 lines
9.0 KiB

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=100, 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 imagePiex(filePath,piex):
# 打开图片
image = Image.open(filePath)
# 设置新的最大宽度和高度
max_size = (piex, piex)
# 保持宽高比缩放图片
image.thumbnail(max_size)
# 保存调整后的图片
image.save(filePath)
def main():
start = time.time()
get_printsize_url = 'https://mp.api.suwa3d.com/api/printOrder/infoByOrderId'
upload_obj_volume_url = 'https://mp.api.suwa3d.com/api/physical/add' # ?pid=1&order_id=1&faces=1&volume=1
print(f'{get_printsize_url}?order_id={orderId}')
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')
imagePath = os.path.join(path, f'{pid}Tex1.jpg')
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')
headcount = res.json()['data']['headcount']
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]
bpy.context.view_layer.objects.active = obj
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}')
if headcount == 1 and height <= 80:
pixs = 4096
faces_dest = 125000
if height <= 50:
pixs = 2048
faces_dest = 63000
print(f'减面到{faces_dest}')
faces_dest = faces_dest * 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")
# imagePiex(imagePath,pixs)
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'))
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=100)
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 -- <orderId>")
sys.exit(1)
orderId = sys.argv[sys.argv.index("--") + 1]
main()