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.
126 lines
4.9 KiB
126 lines
4.9 KiB
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}")
|
|
|