如何将文本渲染为多填充多边形并转直线段以挤出3D三角网格?
将文本挤出为3D三角网格的解决方案
核心思路
利用fontTools提取字体轮廓,借助其内置的贝塞尔曲线细分工具将曲线自动转为直线段,再用trimesh完成挤出操作,无需自行实现曲线转直线的核心逻辑。
步骤1:提取并转换字体轮廓为直线段
通过fontTools加载字体,记录字形路径后,用自带工具将曲线转为满足精度要求的直线段:
from fontTools.ttLib import TTFont from fontTools.pens.recordingPen import RecordingPen from fontTools.misc.bezierTools import splitCubicAtT def convert_curve_to_lines(commands, tolerance=0.1): """将路径命令中的曲线转为直线段,tolerance控制近似精度""" line_commands = [] current_point = None for cmd, args in commands: if cmd == "moveTo": current_point = args[0] line_commands.append(("moveTo", current_point)) elif cmd == "lineTo": line_commands.append(("lineTo", args[0])) current_point = args[0] elif cmd == "curveTo": # 递归细分三次贝塞尔曲线,直到线段足够短 pt1, pt2, pt3 = args _subdivide_cubic_segment(current_point, pt1, pt2, pt3, tolerance, line_commands) current_point = pt3 elif cmd == "closePath": line_commands.append(("closePath",)) return line_commands def _subdivide_cubic_segment(p0, p1, p2, p3, tolerance, line_list): """递归细分贝塞尔曲线生成直线段""" dx, dy = p3[0] - p0[0], p3[1] - p0[1] if dx*dx + dy*dy <= tolerance*tolerance: line_list.append(("lineTo", p3)) return # 拆分曲线为两段,递归处理 t = 0.5 _, _, _, mid_point = splitCubicAtT(p0, p1, p2, p3, t) p0a, p1a, p2a, _ = splitCubicAtT(p0, p1, p2, p3, t) _, p1b, p2b, p3b = splitCubicAtT(p0, p1, p2, p3, 1-t) _subdivide_cubic_segment(p0a, p1a, p2a, mid_point, tolerance, line_list) _subdivide_cubic_segment(mid_point, p1b, p2b, p3b, tolerance, line_list) # 加载目标字体(替换为你的字体路径) font = TTFont("arial.ttf") glyph_set = font.getGlyphSet() # 获取目标字符的字形(这里以字符"A"为例) target_glyph = glyph_set["A"] # 记录字形路径 pen = RecordingPen() target_glyph.draw(pen) # 转换为纯直线段路径 line_path = convert_curve_to_lines(pen.value, tolerance=0.5)
步骤2:用trimesh挤出为3D网格
将转换后的直线段路径转为trimesh可识别的多边形,执行挤出操作:
import trimesh def lines_to_polygons(line_commands): """将直线段命令转为多边形列表""" polygons = [] current_poly = [] for cmd, *args in line_commands: if cmd == "moveTo": if current_poly: polygons.append(current_poly) current_poly = [] current_poly.append(args[0]) elif cmd == "lineTo": current_poly.append(args[0]) elif cmd == "closePath": current_poly.append(current_poly[0]) polygons.append(current_poly) current_poly = [] return polygons # 生成多边形 text_polygons = lines_to_polygons(line_path) # 转为trimesh的2D路径 path_2d = trimesh.load_path(text_polygons) # 挤出为3D网格(height为挤出高度) extruded_mesh = path_2d.extrude(height=2.0) # 保存为STL文件或显示 extruded_mesh.export("text_3d.stl") extruded_mesh.show()
替代方案:基于图像提取轮廓
如果不想处理字体曲线,也可以用PIL生成文本图像,再提取轮廓转3D:
from PIL import Image, ImageDraw import trimesh import numpy as np # 生成文本图像 img = Image.new("L", (200, 100), 0) draw = ImageDraw.Draw(img) draw.text((20, 20), "A", fill=255) # 可指定font参数自定义字体 img_np = np.array(img) # 提取轮廓并挤出 contours = trimesh.util.extract_contours(img_np) mesh = trimesh.extrude(contours[0], height=2.0) mesh.show()
内容的提问来源于stack exchange,提问作者cube
相关产品推荐
相关产品推荐

