149 lines
7.0 KiB
Python
149 lines
7.0 KiB
Python
import bpy
|
|
import bmesh
|
|
|
|
|
|
def active_object(obj):
|
|
bpy.context.view_layer.objects.active = obj
|
|
obj.select_set(True)
|
|
|
|
|
|
def get_obj_max_foot(workdir,filename,filename_tex):
|
|
# 1.模型导入和初始化
|
|
# 删除当前场景中的所有对象:
|
|
# use_global=False表示只删除当前场景中的对象,而不会影响到其他场景中的对象;confirm=False表示删除时不需要确认。
|
|
bpy.ops.object.delete(use_global=False, confirm=False)
|
|
bpy.ops.import_scene.obj(filepath=filename) # 导入指定路径的 OBJ 格式模型文件
|
|
|
|
bpy.context.scene.unit_settings.scale_length = 0.001 # 将场景的长度单位缩放为0.001,相当于将长度单位从默认的米缩小为毫米
|
|
bpy.context.scene.unit_settings.length_unit = 'CENTIMETERS' # 将场景的长度单位设置为厘米
|
|
bpy.context.scene.unit_settings.mass_unit = 'GRAMS' # 将场景的质量单位设置为克
|
|
|
|
obj = bpy.context.selected_objects[0] # 获取了当前选中的对象列表,然后通过 [0] 取得列表中的第一个对象
|
|
bpy.context.view_layer.objects.active = obj # 将变量 obj 设置为当前活动对象
|
|
obj.select_set(True) # 将变量 obj 的选择状态设置为 True,表示选中该对象
|
|
pid = obj.name # 获取该对象的名字
|
|
|
|
# 对选定的对象进行对齐操作
|
|
bpy.ops.object.align(align_mode='OPT_1', relative_to='OPT_1', align_axis={'Z'})
|
|
# 设置选中对象的原点,参数1:将原点设置为对象的质心,参数2:使用对象的几何中心作为参考
|
|
bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS', center='MEDIAN')
|
|
# 将选中对象的位置坐标分别设置为 (0, 0),即将对象移动到世界坐标系的原点位置
|
|
obj.location[0] = 0
|
|
obj.location[1] = 0
|
|
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) # 将选中对象的位置、旋转和缩放应用到对象的数据中
|
|
|
|
# 2.选择要复制的对象
|
|
obj_duplicate = obj.copy()
|
|
obj_duplicate.data = obj.data.copy()
|
|
bpy.context.collection.objects.link(obj_duplicate)
|
|
# obj_duplicate.location.x += 5.0
|
|
bpy.ops.object.select_all(action='DESELECT') # 取消选中全部对象
|
|
|
|
# 3.处理复制的对象的脚底缝合边
|
|
# 选中复制对象
|
|
bpy.context.view_layer.objects.active = obj_duplicate
|
|
obj_duplicate.select_set(True)
|
|
|
|
selected_obj = bpy.context.active_object # 获取当前选中的对象
|
|
bpy.context.view_layer.objects.active = selected_obj # 将对象转换到编辑模式
|
|
|
|
# 切换到3D视图编辑模式
|
|
bpy.context.area.type = 'VIEW_3D'
|
|
bpy.ops.object.mode_set(mode='EDIT')
|
|
bpy.ops.mesh.select_all(action='SELECT') # 选择所有的边
|
|
|
|
# 切换到UV编辑器
|
|
bpy.context.area.type = 'IMAGE_EDITOR'
|
|
pid_img = f"{pid}Tex1.jpg"
|
|
bpy.ops.image.open(filepath=filename_tex, directory=workdir,
|
|
files=[{"name": pid_img, "name": pid_img}], relative_path=True,
|
|
show_multiview=False)
|
|
bpy.context.area.ui_type = 'UV'
|
|
bpy.ops.uv.select_all(action='SELECT') # 选择所有UV贴图顶点
|
|
# 标记所有沿孤岛的边为缝合边
|
|
bpy.ops.uv.seams_from_islands()
|
|
bpy.context.area.type = 'VIEW_3D'
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
|
|
# 获取世界坐标系下z轴接近0的顶点的索引
|
|
z_zero_vertex_indices = []
|
|
for i, vertex in enumerate(selected_obj.data.vertices):
|
|
world_vertex = selected_obj.matrix_world @ vertex.co
|
|
if abs(world_vertex.z) < 0.2:
|
|
z_zero_vertex_indices.append(i)
|
|
# 将对象转换回对象模式
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
# 创建一个新的顶点组,并将z_zero_vertices中的顶点添加到该顶点组中
|
|
vg = selected_obj.vertex_groups.new(name="z_zero_vertices")
|
|
for index in z_zero_vertex_indices:
|
|
vg.add([index], 1.0, 'REPLACE')
|
|
# 将选中的顶点设置为活动顶点
|
|
bpy.ops.object.mode_set(mode='EDIT')
|
|
bpy.ops.mesh.select_all(action='DESELECT')
|
|
bpy.ops.object.vertex_group_select() # 选中待处理的顶点
|
|
bpy.ops.mesh.mark_seam(clear=True) # 取消所选区域内的缝合边
|
|
bpy.ops.mesh.region_to_loop() # 选择选定面周围的边界边!!!
|
|
bpy.ops.mesh.select_mode(type="EDGE") # 转换为线模式
|
|
bpy.ops.mesh.mark_seam(clear=False) # 标记所选的线为缝合边
|
|
|
|
# 选中脚底顶点组
|
|
bpy.ops.uv.select_all(action='DESELECT')
|
|
bpy.ops.object.vertex_group_set_active(group='z_zero_vertices') # 设置活动顶点组
|
|
bpy.ops.object.vertex_group_select() # 选择分配给活动顶点组的所有顶点
|
|
bpy.ops.uv.unwrap()
|
|
|
|
# 处理贴图脚底部分孤岛,其他孤岛保持不变
|
|
# (1)反选模型顶点,方便贴图固定不需要处理的区域
|
|
bpy.ops.mesh.select_all(action='INVERT')
|
|
bpy.context.area.type = 'IMAGE_EDITOR' # 切换到贴图模式
|
|
bpy.context.area.ui_type = 'UV'
|
|
bpy.ops.uv.pin(clear=False)
|
|
bpy.ops.object.vertex_group_set_active(group='z_zero_vertices') # 设置活动顶点组
|
|
bpy.ops.object.vertex_group_select() # 选择分配给活动顶点组的所有顶点
|
|
# (2)脚底部位UV展开,平均孤岛比例,重新排列孤岛
|
|
bpy.ops.uv.select_all(action='SELECT')
|
|
bpy.ops.uv.average_islands_scale()
|
|
bpy.ops.uv.pack_islands(margin=0.001)
|
|
|
|
bpy.context.area.type = 'VIEW_3D'
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
|
|
# 4. 烘焙模式,参数设置
|
|
bpy.ops.object.select_all(action='DESELECT') # 取消选中全部对象
|
|
# # 选中原始对象
|
|
bpy.context.view_layer.objects.active = obj
|
|
obj.select_set(True)
|
|
# 选中复制对象
|
|
bpy.context.view_layer.objects.active = obj_duplicate
|
|
obj_duplicate.select_set(True)
|
|
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_selected_to_active = True
|
|
bpy.context.scene.render.bake.cage_extrusion = 0.01
|
|
bpy.ops.object.bake(type='DIFFUSE') # 开始 Bake
|
|
|
|
# 5. 导出模型和贴图
|
|
bpy.ops.object.select_all(action='DESELECT') # 取消选中全部对象
|
|
# 选中复制对象
|
|
bpy.context.view_layer.objects.active = obj_duplicate
|
|
obj_duplicate.select_set(True)
|
|
bpy.ops.wm.obj_export(filepath=filename, export_selected_objects=True)
|
|
bpy.context.area.type = 'IMAGE_EDITOR' # 切换到
|
|
bpy.ops.image.save_as(filepath=filename_tex)
|
|
bpy.context.area.type = 'TEXT_EDITOR' # 切换到文本编辑器
|
|
|
|
|
|
if __name__ == '__main__':
|
|
workdir = 'E:\\117080\\print_model'
|
|
# filename = f'{workdir}\\117080_12cm_x1.obj'
|
|
filename = f'{workdir}\\117080.obj'
|
|
filename_tex = f'{workdir}\\117080Tex1.jpg'
|
|
save_obj = f"{workdir}\\bake\\117080Tex1.obj"
|
|
save_tex = f"{workdir}\\bake\\117080Tex1.jpg"
|
|
|
|
get_obj_max_foot() |