import bpy, sys, time, math def clear_default_objects(): for name in ["Cube", "Light", "Camera"]: if obj := bpy.data.objects.get(name): bpy.data.objects.remove(obj) def mark_sharp_edges(obj, angle=30): bpy.context.view_layer.objects.active = obj bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='SELECT') # 标记30°以上的边为锐边 bpy.ops.mesh.edges_select_sharp(sharpness=math.radians(angle)) bpy.ops.mesh.mark_sharp() bpy.ops.object.mode_set(mode='OBJECT') def planar_decimate(obj, angle_limit=35.0, ratio=0.5, protect_uv=True): """使用Decimate修改器+智能参数配置""" print(f"启动高级减面流程 | 模式: 平面优化+权重控制") #""" # 添加Decimate修改器(平面模式) mod = obj.modifiers.new(name="PlanarDecimate", type='DECIMATE') mod.decimate_type = 'DISSOLVE' # 平面溶解模式 mod.angle_limit = math.radians(angle_limit) # 角度转弧度 mod.use_dissolve_boundaries = False # 溶解边界防止破面[5](@ref) #""" """ mod = obj.modifiers.new(name="CollapseDecimate", type='DECIMATE') mod.decimate_type = 'COLLAPSE' mod.ratio = 0.1 # 保留30%面数 mod.use_symmetry = True mod.vertex_group = "high_detail" # 绑定顶点组保护细节区域 #""" # 保护关键属性 mod.delimit = {'NORMAL', 'UV'} if protect_uv else {'NORMAL'} # UV保护[1](@ref) mod.use_symmetry = True # 对称保护[1](@ref) # 保护边界:创建顶点组标记轮廓边 if "boundary_edges" not in obj.vertex_groups: obj.vertex_groups.new(name="boundary_edges") mod.vertex_group = "boundary_edges" mod.invert_vertex_group = True # 仅减非边界区域 # 应用修改器 bpy.context.view_layer.objects.active = obj bpy.ops.object.modifier_apply(modifier=mod.name) print(f"平面优化完成 | 容差角: {angle_limit}°") def collapse_decimate(obj, ratio=0.3, protect_groups=True): """核心减面:Collapse模式+细节保护""" mod = obj.modifiers.new(name="CollapseDecimate", type='DECIMATE') mod.decimate_type = 'COLLAPSE' mod.ratio = ratio # 顶点组保护(需提前在Blender中标记高细节区域)[1](@ref) if protect_groups and "high_detail" in obj.vertex_groups: mod.vertex_group = "high_detail" mod.invert_vertex_group = True # 仅减非保护区域 print("启用顶点组保护 | 保留高细节区域") # 关键保护设置 mod.use_symmetry = True bpy.ops.object.modifier_apply(modifier=mod.name) print(f"塌陷减面完成 | 保留比例: {ratio*100}%") def triangulate_mesh(obj, quad_method='BEAUTY', ngon_method='BEAUTY'): """将模型三角化[1,2](@ref)""" print("启动三角化处理...") # 添加三角化修改器 mod = obj.modifiers.new(name="Triangulate", type='TRIANGULATE') mod.quad_method = quad_method # 四边形处理方法 mod.ngon_method = ngon_method # 多边形处理方法 mod.min_vertices = 4 # 对四边形及以上面进行三角化 # 应用修改器 bpy.context.view_layer.objects.active = obj bpy.ops.object.modifier_apply(modifier=mod.name) # 验证三角化结果 tris = sum(1 for poly in obj.data.polygons if len(poly.vertices) == 3) total_faces = len(obj.data.polygons) print(f"三角化完成 | 三角面比例: {tris/total_faces*100:.1f}% ({tris}/{total_faces})") def optimize_geometry(obj): """后处理:清理拓扑+法线修复[1,6](@ref)""" bpy.context.view_layer.objects.active = obj bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.remove_doubles(threshold=0.001) # 合并重复顶点 bpy.ops.mesh.normals_make_consistent() # 统一法线 bpy.ops.object.mode_set(mode='OBJECT') print("拓扑清理完成 | 法线已重计算") if __name__ == "__main__": argv = sys.argv[sys.argv.index("--") + 1:] input_path = argv[0] angle_limit = float(argv[1]) if len(argv) > 1 else 5.0 output_path = argv[2] if len(argv) > 2 else input_path.replace(".ply", "_decimated.ply") # 硬件加速配置 # bpy.context.scene.cycles.device = 'GPU' # bpy.context.preferences.system.memory_cache_limit = 4096 clear_default_objects() # 导入PLY模型 bpy.ops.wm.ply_import(filepath=input_path) obj = bpy.context.selected_objects[0] print(f"开始减面操作:{obj.name}") # 执行减面 mark_sharp_edges(obj) planar_decimate(obj, angle_limit) # 先平面优化 collapse_decimate(obj, ratio=0.2) # 再智能塌陷 // 0.1-3效果好,0.2-3综合不错 optimize_geometry(obj) # 最终清理 triangulate_mesh(obj) print("减面完成") bpy.ops.wm.ply_export( filepath=output_path, apply_modifiers=False ) print(f"模型已导出至:{output_path}")