如何通过Blender Python API将眼镜架部件(鼻梁、镜腿、镜片、鼻托)作为统一几何单元操作,并实现iOS app实时控制的参数化调整?
如何通过Blender Python API将眼镜架部件(鼻梁、镜腿、镜片、鼻托)作为统一几何单元操作,并实现iOS app实时控制的参数化调整?
嘿,我来帮你搞定这个眼镜架参数化调整的问题!你之前遇到的那些扭曲变形,根源是没用到Blender专为部件级操作设计的工具,咱们一步步来拆解解决方案:
核心方案选型:优先用「独立部件+适配变形工具」组合
先说说你之前的方法为啥不行:
- 直接按位置/范围选顶点操作:本质还是单个顶点的独立移动,完全没考虑部件的几何连续性,必然会出现 jagged(锯齿状)变形
- 比例编辑:手动调着好用,但程序化控制精度太低,没法保证实时调整的一致性
我推荐的组合思路:
- 先拆分部件为独立Mesh对象:把导入的STL拆成鼻梁、镜腿、镜片框、鼻托这些独立对象——只有独立对象才能做整体变换,同时不破坏自身几何结构
- 针对不同部件用适配的变形工具:
- 鼻梁、镜腿:用几何节点或骨骼绑定做参数化变形,保证曲线平滑
- 镜片框:用形状键或约束维持圆形/椭圆形的规整性
- 鼻托:直接做整体平移/缩放就行,因为是简单几何体
- 用Python封装参数化接口:把每个部件的调整逻辑写成你要的
adjust_bridge_width()这类函数,再暴露成REST接口给iOS调用
第一步:预处理STL模型,拆分独立部件
首先你需要把导入的单个STL拆成多个部件对象。可以先在Blender里手动给每个部件创建顶点组,再用脚本拆分:
import bpy def split_mesh_by_vertex_groups(obj): bpy.context.view_layer.objects.active = obj # 遍历每个预先创建的顶点组(比如"Bridge"、"LeftTemple"等) for vgroup in obj.vertex_groups: # 选中当前顶点组的所有顶点 bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='DESELECT') bpy.ops.object.vertex_group_select(group_name=vgroup.name) # 分离选中顶点为新对象 bpy.ops.mesh.separate(type='SELECTED') bpy.ops.object.mode_set(mode='OBJECT') # 给新对象命名为顶点组名称 new_obj = bpy.context.selected_objects[-1] new_obj.name = vgroup.name # 假设你的眼镜架主对象叫"EyeglassFrame" frame_obj = bpy.data.objects["EyeglassFrame"] split_mesh_by_vertex_groups(frame_obj)
执行后你会得到Bridge、LeftTemple、RightLensFrame、NosePads这些独立对象,后续就可以单独操作每个部件了。
第二步:给每个部件实现参数化调整
1. 鼻梁(Bridge):用几何节点做平滑缩放/弯曲
几何节点是Blender 3.x里最适合程序化平滑变形的工具,能完美维持鼻梁的曲线:
- 给Bridge对象添加「几何节点」修改器,打开几何节点编辑器
- 添加边界框中心节点获取鼻梁的中心,作为缩放原点
- 添加缩放元素节点,把X轴缩放值连接到一个Float参数输入(命名为
WidthScale) - 用Python控制这个参数即可:
def adjust_bridge_width(scale_factor): bridge_obj = bpy.data.objects["Bridge"] # 获取几何节点树里的宽度参数 geo_mod = bridge_obj.modifiers["GeometryNodes"] width_param = geo_mod.node_group.inputs["WidthScale"] width_param.default_value = scale_factor # 实时更新视图 bpy.context.view_layer.update()
如果要调整曲率,只需要添加弯曲节点,用另一个参数控制弯曲角度就行。
2. 镜片框(LensFrames):用形状键维持圆形规整性
镜片框不能缩放成多边形,形状键是最稳妥的方案:
- 手动创建几个基础形状:比如默认大小、缩小10%、放大10%的镜片框形状键
- 用Python控制形状键的混合值实现平滑过渡:
def adjust_lens_size(scale_factor): left_lens = bpy.data.objects["LeftLensFrame"] right_lens = bpy.data.objects["RightLensFrame"] # 计算形状键混合值(scale_factor=1对应默认大小,0.9对应缩小10%) mix_value = 1 - (1 - scale_factor) left_lens.data.shape_keys.key_blocks["Scale"].value = mix_value right_lens.data.shape_keys.key_blocks["Scale"].value = mix_value bpy.context.view_layer.update()
3. 镜腿(Temples):用骨骼绑定维持锥形和曲线
镜腿需要保持 taper(锥形)和原有曲线,骨骼绑定是最佳选择:
- 给镜腿添加Armature,创建2根骨骼:一根在镜腿根部,一根在末端
- 用「自动权重」把骨骼绑定到镜腿Mesh
- 用Python控制骨骼长度实现镜腿延长/缩短:
def adjust_temple_length(scale_factor): left_armature = bpy.data.objects["LeftTempleArmature"] right_armature = bpy.data.objects["RightTempleArmature"] # 调整左侧镜腿末端骨骼长度 bpy.context.view_layer.objects.active = left_armature bpy.ops.object.mode_set(mode='EDIT') left_armature.data.bones["TempleEnd"].length *= scale_factor bpy.ops.object.mode_set(mode='OBJECT') # 右侧同理 bpy.context.view_layer.objects.active = right_armature bpy.ops.object.mode_set(mode='EDIT') right_armature.data.bones["TempleEnd"].length *= scale_factor bpy.ops.object.mode_set(mode='OBJECT') bpy.context.view_layer.update()
要调整粗细的话,给骨骼添加缩放约束,控制根部到末端的锥形比例即可。
4. 鼻托(NosePads):整体平移/缩放
鼻托是简单几何体,直接做整体变换就能满足需求:
def adjust_nose_pad_spacing(scale_factor): nose_pads = bpy.data.objects["NosePads"] # 以鼻托中心为原点缩放X轴(左右间距) center = nose_pads.location # 用矩阵变换保证缩放围绕中心进行 nose_pads.location = (0,0,0) nose_pads.scale.x *= scale_factor nose_pads.location = center bpy.context.view_layer.update()
第三步:实现REST API接口,支持iOS实时控制
用Flask框架把上面的函数暴露成HTTP接口,让iOS app通过REST调用:
from flask import Flask, request import bpy app = Flask(__name__) # 调整鼻梁宽度的接口 @app.route('/adjust/bridge-width', methods=['POST']) def api_bridge_width(): data = request.json scale = data.get('scale_factor', 1.0) adjust_bridge_width(scale) # 导出更新后的STL用于3D打印 bpy.ops.export_mesh.stl(filepath="/tmp/updated_frame.stl", use_selection=True) return {"status": "success", "stl_path": "/tmp/updated_frame.stl"} # 其他调整接口同理 @app.route('/adjust/lens-size', methods=['POST']) def api_lens_size(): data = request.json scale = data.get('scale_factor', 1.0) adjust_lens_size(scale) bpy.ops.export_mesh.stl(filepath="/tmp/updated_frame.stl", use_selection=True) return {"status": "success"} if __name__ == '__main__': # 用Blender的Python解释器启动Flask,监听所有IP app.run(host='0.0.0.0', port=5000)
注意:需要给Blender的Python环境安装Flask,执行pip install flask --target=/path/to/blender/python/site-packages即可。
第四步:保障性能和3D打印兼容性
- 性能优化:
- 只在必要时调用
bpy.context.view_layer.update(),避免频繁刷新视图 - 几何节点和骨骼绑定的变形都是GPU加速的,3000顶点的模型完全能支持实时调整
- 只在必要时调用
- 打印性保障:
- 变形后执行
bpy.ops.mesh.remove_doubles()消除重复顶点 - 用
bpy.ops.mesh.normals_make_consistent()确保法线一致,避免自相交 - 导出STL前应用所有修改器,保证模型是可打印的实体
- 变形后执行
内容来源于stack exchange




