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

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}")