Blender文本输入插件开发遇阻:bpy安装及字体路径错误
Blender插件开发报错:
bpy.utils.user_resource('FONTS')参数无效 问题背景
我用PyCharm开发Blender的bpy文本输入插件,计划实现以下功能:
- 通过UI输入两行文本
- 调用通用位置的自定义字体
- 将文本导入并转为网格对象
- 创建曲线并让文本对齐曲线
- 设置Text_1和Text_2的X轴旋转90度
但插件运行时触发报错,提示bpy.utils.user_resource('FONTS')参数无效,该函数仅接受('DATAFILES', 'CONFIG', 'SCRIPTS', 'AUTOSAVE')类型的参数。
报错详情
Python: Traceback (most recent call last): File "C:\Foundation\Blender\4.1\scripts\addons\_init4_.py", line 75, in execute self.process_field1_text(context, text1) File "C:\Foundation\Blender\4.1\scripts\addons\_init4_.py", line 132, in process_field1_text font_path = os.path.join(bpy.utils.user_resource('FONTS'), "My decorative font.ttf") ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\4.1\4.1\scripts\modules\bpy\utils\__init__.py", line 749, in user_resource target_path = _user_resource(resource_type, path=path) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ValueError: expected a string in ('DATAFILES', 'CONFIG', 'SCRIPTS', 'AUTOSAVE'), got 'FONTS'
插件代码
classes = ( TextImporterProperties, TEXT_PT_importer_panel, TEXT_OT_import_to_blender, ) # Registration def register(): for cls in classes: bpy.utils.register_class(cls) bpy.types.Scene.text_importer_props = bpy.props.PointerProperty(type=TextImporterProperties) def unregister(): for cls in reversed(classes): bpy.utils.unregister_class(cls) del bpy.types.Scene.text_importer_props import bpy.ops.curve.primitive_bezier_circle_add (radius=1, enter_editmode+False, align_'WORLD', location=(0, 0, 0), scale=(1, 1, 1)) as bpy import os from bpy.props import StringProperty # Custom properties to store the text field values class TextImporterProperties(bpy.types.PropertyGroup): text_field_1: StringProperty( name="Text Field 1", description="Enter text for field 1", default="" ) text_field_2: StringProperty( name="Text Field 2", description="Enter text for field 2", default="" ) # Panel to display the text fields class TEXT_PT_importer_panel(bpy.types.Panel): bl_label = "Text Importer" bl_idname = "TEXT_PT_importer" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'Text Importer' def draw(self, context): layout = self.layout scene = context.scene text_props = scene.text_importer_props # Text Field 1 layout.label(text="Text Field 1:") layout.prop(text_props, "text_field_1", text="") # Text Field 2 layout.label(text="Text Field 2:") layout.prop(text_props, "text_field_2", text="") # Import button layout.separator() layout.operator("text.import_to_blender", text="Import Text") # Operator to handle the import action class TEXT_OT_import_to_blender(bpy.types.Operator): bl_idname = "text.import_to_blender" bl_label = "Import Text to Blender" bl_description = "Import the text from both fields into Blender" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): scene = context.scene text_props = scene.text_importer_props text1 = text_props.text_field_1 text2 = text_props.text_field_2 # Process text from Field 1 if text1: self.process_field1_text(context, text1) # Process text from Field 2 if text2: self.process_field2_text(context, text2) self.report({'INFO'}, "Text imported and processed successfully") return {'FINISHED'} def create_text_object(self, context, text_content, name, location): # Create a new text curve data block text_curve = bpy.data.curves.new(type="FONT", name=name) text_curve.body = text_content # Create a new object with the text curve text_obj = bpy.data.objects.new(name, text_curve) text_obj.location = location # Link the object to the current collection context.collection.objects.link(text_obj) return text_obj def create_cylinder(self, context, name): # Add a cylinder bpy.ops.mesh.primitive_cylinder_add(vertices=146, radius=2.5, depth=4.0) cylinder = context.active_object cylinder.name = name # Set cap fill type to "Nothing" bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.delete(type='ONLY_FACE') bpy.ops.object.mode_set(mode='OBJECT') # Set location X to 0 - Test set for offset if needed cylinder.location.x = 0.0 def process_field1_text(self, context, text_content): # Create text object text_obj = self.create_text_object(context, text_content, "Field1Text", (0, 0, 0)) # Select the text object bpy.ops.object.select_all(action='DESELECT') text_obj.select_set(True) context.view_layer.objects.active = text_obj ------- # Convert text to curve bpy.ops.object.convert(target='CURVE') # Create cylinder for text deformation cylinder = self.create_cylinder(context, "Field1Cylinder") # Select the text again bpy.ops.object.select_all(action='DESELECT') text_obj.select_set(True) context.view_layer.objects.active = text_obj # Set geometry taper object to cylinder text_obj.data.taper_object = cylinder # Add curve modifier curve_modifier = text_obj.modifiers.new(name="Curve", type='CURVE') curve_modifier.object = cylinder # Set rotation X to -90 degrees text_obj.rotation_euler.x = -1.5708 # -90 degrees in radians return text_obj def process_field2_text(self, context, text_content): # Create text object text_obj = self.create_text_object(context, text_content, "Field2Text", (0, 0, 0)) # Select the text object bpy.ops.object.select_all(action='DESELECT') text_obj.select_set(True) context.view_layer.objects.active = text_obj ------- # Convert text to curve bpy.ops.object.convert(target='CURVE') # Create cylinder for text deformation cylinder = self.create_cylinder(context, "Field2Cylinder") # Select the text again bpy.ops.object.select_all(action='DESELECT') text_obj.select_set(True) context.view_layer.objects.active = text_obj # Set geometry taper object to cylinder text_obj.data.taper_object = cylinder # Add curve modifier curve_modifier = text_obj.modifiers.new(name="Curve", type='CURVE') curve_modifier.object = cylinder # Set deform axis to -X curve_modifier.deform_axis = 'NEG_X' return text_obj if __name__ == "__main__": register()
修复方案
1. 替换字体路径获取的错误写法
Blender的bpy.utils.user_resource不支持'FONTS'参数,可通过以下两种方式获取字体路径:
方法一:用bpy.utils.system_resource获取系统字体目录
font_path = os.path.join(bpy.utils.system_resource('FONT'), "My decorative font.ttf")
方法二:手动指定插件内的字体路径
如果自定义字体放在插件目录的fonts文件夹下,可直接用相对路径:
addon_dir = os.path.dirname(os.path.abspath(__file__)) font_path = os.path.join(addon_dir, "fonts", "My decorative font.ttf")
2. 修复代码中的语法错误
原代码存在两处语法问题,需修正:
- 删除错误的导入语句:
import bpy.ops.curve.primitive_bezier_circle_add及后续括号代码,直接用import bpy即可。 - 删除
process_field1_text和process_field2_text函数中的-------注释,避免语法报错。
修正后的字体加载示例代码:
# 替换错误的导入部分 import bpy import os from bpy.props import StringProperty # ... 其他代码保持不变 def process_field1_text(self, context, text_content): # Create text object text_obj = self.create_text_object(context, text_content, "Field1Text", (0, 0, 0)) # Select the text object bpy.ops.object.select_all(action='DESELECT') text_obj.select_set(True) context.view_layer.objects.active = text_obj # 加载自定义字体 font_path = os.path.join(bpy.utils.system_resource('FONT'), "My decorative font.ttf") if os.path.exists(font_path): font = bpy.data.fonts.load(font_path) text_obj.data.font = font # Convert text to curve bpy.ops.object.convert(target='CURVE') # ... 后续代码保持不变
内容的提问来源于stack exchange,提问作者William Rickard
相关产品推荐
相关产品推荐

