4 changed files with 251 additions and 20 deletions
@ -0,0 +1,223 @@ |
|||||||
|
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.gray.api.suwa3d.com/api/printOrder/infoByOrderId' |
||||||
|
upload_obj_volume_url = 'https://mp.gray.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() |
||||||
Loading…
Reference in new issue