同步更改数据

This commit is contained in:
dongchangxi committed 2024-07-17 14:46:47 +08:00
1 parent ecb58b2f59
commit 33ba8bb357
21 files changed
+2019472 -63

No files matched your search

+273
View File
@@ -0,0 +1,273 @@
import os, sys, time, argparse, requests, json, re, oss2
import bpy, bmesh
import open3d as o3d
import numpy as np
# import cupy as cp
from mathutils import Matrix
import math
import logging
import matplotlib.pyplot as plt
def remove_nan_verts(obj):
'''删除模型中空坐标的顶点'''
# obj = bpy.context.active_object
if obj.mode == 'EDIT':
bm = bmesh.from_edit_mesh(obj.data)
else:
bm = bmesh.new()
bm.from_mesh(obj.data)
nans = [v for v in bm.verts if any(c != c for c in v.co)]
bmesh.ops.delete(bm, geom=nans, context='VERTS')
degenerates = [f for f in bm.faces if len(f.verts) < 3]
bmesh.ops.delete(bm, geom=degenerates, context='FACES')
if obj.mode == 'EDIT':
bmesh.update_edit_mesh(obj.data)
else:
bm.to_mesh(obj.data)
obj.data.update()
print("NAN vertices and degenerate faces removed.")
def getHeadCount(pid):
get_printinfo_url = 'https://mp.api.suwa3d.com/api/customerP3dLog/printInfo'
res = requests.get(get_printinfo_url, params={'id': pid})
print('get_printinfo_url:', res.url)
print('res:', res.text)
if res.status_code != 200:
print('获取人数失败,程序退出')
exit(1)
res = json.loads(res.text)
return res['data']['headcount']
def get_obj_bake_vertex_ply(obj_filepath, save_ply_path):
start_time = time.time()
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}: Getting ply vertex from {obj_filepath}')
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_by_type(type='MESH')
bpy.ops.object.delete(use_global=False, confirm=False)
bpy.ops.wm.obj_import(filepath=obj_filepath)
obj_original = [obj for obj in bpy.data.objects if obj.type == 'MESH'][0]
bpy.context.view_layer.objects.active = obj_original
obj_original.select_set(True)
pid = obj_original.name
obj_num_vertices = len(obj_original.data.vertices)
# print(f"模型 {pid} 顶点数量:", len(obj_original.data.vertices))
# 选择新分离出来的网格对象,并将该对象设为进活动对象
bpy.ops.object.select_all(action='DESELECT')
bpy.context.view_layer.objects.active = obj_original
obj_original.select_set(True)
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}: Split foot time: ', time.time() - start_time)
start_time = time.time()
# 表面细分Subdivision Surface,如果细分后定点数目大于目标数目,停止循环细分
# target_verts = len(obj_original.data.vertices) * 8
try:
target_verts = getHeadCount(pid) * 2000000
except TypeError as e:
return 0
mesh_data = obj_original.data
obj_original_name = obj_original.name
# Blender 网格对象的顶点数据转换为 Open3D 格式
o3d_mesh = o3d.geometry.TriangleMesh()
o3d_mesh.vertices = o3d.utility.Vector3dVector([v.co for v in mesh_data.vertices])
o3d_mesh.triangles = o3d.utility.Vector3iVector([f.vertices for f in mesh_data.polygons])
o3d_mesh.compute_vertex_normals() # 计算顶点法线
# open3d 细分操作
for i in range(2, 8):
mesh_subdivided = o3d_mesh.subdivide_loop(number_of_iterations=i)
subdivision_vertex_count = len(mesh_subdivided.vertices)
if subdivision_vertex_count > target_verts:
break
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}: Subdivision time: ', time.time() - start_time)
start_time = time.time()
# open3d 减面操作
# 官网文档介绍简化网格不能保证一定会达到这个数字
target_triangles = target_verts * 2
mesh_smp = mesh_subdivided.simplify_quadric_decimation(target_number_of_triangles=target_triangles)
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}: Decimation time: ', time.time() - start_time)
start_time = time.time()
# 将open3d网格转换回blender网格
o3d_to_blender_mesh = bpy.data.meshes.new(name=f"{obj_original_name}_decimation")
o3d_to_blender_mesh.from_pydata(mesh_smp.vertices, [], mesh_smp.triangles)
o3d_to_blender_mesh.update()
obj_open3d = bpy.data.objects.new(f"{obj_original_name}_decimation", o3d_to_blender_mesh)
# 设置新对象的位置和旋转信息,等于原始模型的信息
obj_open3d.location = obj_original.location
obj_open3d.rotation_euler = obj_original.rotation_euler
obj_open3d.scale = obj_original.scale
bpy.context.collection.objects.link(obj_open3d)
# 开始将obj_mesh的贴图颜色烘焙到open3d模型上
# 复制对象作为罩体
obj_cage = obj_open3d.copy()
obj_cage.data = obj_open3d.data.copy()
bpy.context.collection.objects.link(obj_cage)
obj_cage.name = f"{obj_original_name}_cage"
bpy.ops.object.select_all(action='DESELECT')
bpy.context.view_layer.objects.active = obj_open3d
obj_open3d.select_set(True)
bpy.ops.object.mode_set(mode='EDIT')
bpy.context.scene.tool_settings.use_uv_select_sync = True # 同步3D_View和UV编辑模式选中顶点部分
bpy.ops.uv.smart_project()
bpy.ops.uv.select_overlap()
bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=0)
bpy.ops.uv.select_all(action='SELECT')
bpy.ops.uv.average_islands_scale()
bpy.ops.uv.pack_islands(margin=0)
bpy.ops.object.mode_set(mode='OBJECT')
# 新建open3d模型的材质
open3dMat = bpy.data.materials.new(name='Mat_open3d')
obj_open3d.data.materials.append(open3dMat)
open3dMat.use_nodes = True
nodes = open3dMat.node_tree.nodes
prin_bsdf_node = nodes.get("Principled BSDF")
# 创建新的贴图对象
tex_image_node = nodes.new("ShaderNodeTexImage")
tex_image = bpy.data.images.new(name="o3d_teximage", width=8192, height=8192)
tex_image_node.image = tex_image
tex_image_node.location = (-400, 200)
tex_image_node.select = True # 节点选中状态
tex_image_node.select = True # 节点为活动状态
links = open3dMat.node_tree.links
bpy.context.object.active_material = open3dMat
bpy.ops.object.material_slot_select()
bpy.ops.object.material_slot_assign()
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}: Prepare bake data time: ', time.time() - start_time)
start_time = time.time()
# 烘焙操作
bpy.context.scene.render.engine = 'CYCLES'
bpy.context.scene.cycles.device = 'GPU'
bpy.context.scene.cycles.preview_samples = 1
bpy.context.scene.cycles.samples = 1
bpy.context.scene.cycles.bake_type = 'DIFFUSE'
bpy.context.scene.render.bake.use_pass_direct = False
bpy.context.scene.render.bake.use_pass_indirect = False
bpy.context.scene.render.bake.use_pass_color = True
bpy.context.scene.render.bake.use_selected_to_active = True
bpy.context.scene.render.bake.use_cage = True
bpy.context.scene.render.bake.cage_object = bpy.data.objects[obj_cage.name]
bpy.context.scene.render.bake.target = 'IMAGE_TEXTURES'
# 添加置换修改器,不能应用
bpy.ops.object.select_all(action='DESELECT')
bpy.context.view_layer.objects.active = obj_cage
obj_cage.select_set(True)
bpy.ops.object.modifier_add(type='DISPLACE')
bpy.context.object.modifiers["Displace"].mid_level = 0.995
bpy.ops.object.modifier_apply(modifier="Displace")
bpy.ops.object.select_all(action='DESELECT')
bpy.context.view_layer.objects.active = obj_original
obj_original.select_set(True)
bpy.context.view_layer.objects.active = obj_open3d
obj_open3d.select_set(True)
bpy.ops.object.bake(type='DIFFUSE') # 开始 Bake
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}: Bake DIFFUSE time: ', time.time() - start_time)
start_time = time.time()
links.new(tex_image_node.outputs[0], prin_bsdf_node.inputs[0])
bpy.data.objects.remove(obj_original, do_unlink=True)
bpy.data.objects.remove(obj_cage, do_unlink=True)
# 添加颜色属性
bpy.ops.geometry.color_attribute_add()
# 节点的创建:
# nodes = bpy.context.active_object.active_material.node_tree.nodes
# links = bpy.context.active_object.active_material.node_tree.links
tex_coord = nodes.new("ShaderNodeTexCoord")
Mapping = nodes.new('ShaderNodeMapping')
vertex_color = nodes.new("ShaderNodeVertexColor")
tex_coord.location = (-800, 600)
Mapping.location = (-500, 200)
vertex_color.location = (-200, 800)
# 节点之间的连接:
# 纹理坐标的UV 连接 映射的矢量;映射的矢量 连接 纹理贴图的矢量;原理化BSDF删除;纹理贴图的矢量 连接 表(曲)面。
links.new(tex_coord.outputs[2], nodes['Mapping'].inputs[0])
links.new(Mapping.outputs[0], nodes['Image Texture'].inputs[0])
principled_bsdf = nodes.get("Principled BSDF")
nodes.remove(principled_bsdf)
links.new(nodes['Image Texture'].outputs[0], nodes['Material Output'].inputs[0])
# 4.渲染烘焙相关操作
bpy.context.scene.render.engine = 'CYCLES'
bpy.context.scene.cycles.device = 'GPU'
bpy.context.scene.cycles.preview_samples = 1
bpy.context.scene.cycles.samples = 1
bpy.context.scene.cycles.bake_type = 'EMIT'
bpy.context.scene.render.bake.use_selected_to_active = False
bpy.context.scene.render.bake.target = 'VERTEX_COLORS'
bpy.ops.object.bake(type='EMIT') # 开始 Bake
# 连接节点 Color Attribute 和 节点 Material Output
links.new(nodes['Color Attribute'].outputs[0], nodes['Material Output'].inputs[0])
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}: Bake EMIT time: ', time.time() - start_time)
start_time = time.time()
# 清除顶点为nan的无效数据
bpy.ops.object.select_all(action='DESELECT')
bpy.context.view_layer.objects.active = obj_open3d
obj_open3d.select_set(True)
remove_nan_verts(obj_open3d)
# 5.输出模型
# bpy.ops.wm.save_as_mainfile(filepath='/data/datasets/plys/121614.bend')
bpy.ops.wm.ply_export(filepath=save_ply_path, apply_modifiers=True, export_selected_objects=True, export_uv=False,
export_normals=False, export_colors='SRGB', export_triangulated_mesh=False, ascii_format=True)
bpy.data.objects.remove(obj_open3d, do_unlink=True)
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}: Save ply time: ', time.time() - start_time)
return obj_num_vertices
if __name__ == '__main__':
# workdir = '/data/datasets/suwa_cut/data/auto/'
# output = '/data/datasets/plys/auto/'
workdir = 'G:\obj_fix\print'
output = 'G:\obj_fix\ply\whole_obj_bake_vertex_high_ply'
directory = f'G:\obj_fix/print/right'
#遍历获取 G:\obj_fix\print\right 目录的文件,根据文件名获取 pid
for file_name in os.listdir(directory):
# 获取文件的完整路径
file_path = os.path.join(directory, file_name)
# 检查是否是文件
if os.path.isfile(file_path):
#
arrFileName = file_name.split('_')
pid = arrFileName[0]
if int(pid) == 0:
continue
print(f"File: {file_name}, PID: {pid}")
#判断文件是否存在
file_path = os.path.join(output, f'{pid}.ply')
if os.path.exists(file_path) and os.path.isfile(file_path):
print("文件已存在,跳过循环!!!")
continue
obj_filepath = os.path.join(workdir, f'{pid}/{pid}.obj')
save_ply_path = os.path.join(output, f'{pid}.ply')
if not os.path.exists(obj_filepath):
print(f"{obj_filepath} 文件不存在,跳过循环!!!")
continue
obj_num_vertices = get_obj_bake_vertex_ply(obj_filepath, save_ply_path)
if obj_num_vertices == 0:
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}: 模型 {pid} 程序getHeadCount()无法找到模型人数!总共运行时间: ', time.time() - start_time0)
logging.info(f'模型 {pid} 顶点数量: {obj_num_vertices},程序getHeadCount()无法找到模型人数!,程序总共运行时间: {time.time() - start_time0:.2f} 秒')
continue