Blender几何节点插件报错:'module'对象无'inputs'属性求解决
修复Pick Node Generator插件的AttributeError错误
错误原因
你遇到的AttributeError: 'module' object has no attribute 'inputs'是因为代码中把创建的NodeGroupInput节点命名为input,而input是Python的内置模块名称,导致后续调用input.outputs时,Python错误地将其识别为内置模块,而非你创建的节点对象,因此找不到对应属性。
修复步骤
- 将代码中所有指代
NodeGroupInput节点的input变量名替换为非内置关键字/模块名(比如group_input) - 同步修改所有引用该节点的代码行,确保变量名一致
修正后的完整代码
import bpy from bpy.props import IntProperty, EnumProperty bl_info = { "name": "Pick Node Generator", "author": "Johnny Matthews", "location": "Geometry Nodes Editor: Add Node Panel", "version": (1, 0), "blender": (3, 4, 1), "description": "Add a customizable pick node", "category": "Nodes" } def find_socket(list, type, name): for s in list: if s.type == type and s.name == name: return s def main(self, context): space = context.space_data if space.node_tree == None: return group = space.node_tree cases = self.cases type_enum = self.type type = 'NodeSocket'+type_enum.capitalize() if type_enum == "RGBA": type = 'NodeSocketColor' if type_enum == "BOOLEAN": type = 'NodeSocketBool' if type_enum == "VALUE": type = 'NodeSocketFloat' tree = bpy.data.node_groups.new("test", 'GeometryNodeTree') tree.name = type_enum.capitalize() + ' Pick x'+str(cases) socket_case = tree.inputs.new('NodeSocketInt', 'Switch') for i in range(cases): socket_case = tree.inputs.new(type, 'Case '+str(i+self.start)+":") tree.inputs.new(type, 'Default ') socket_output = tree.outputs.new(type, 'Output') # 替换变量名,避免和内置input模块冲突 group_input = tree.nodes.new("NodeGroupInput") group_input.location = (0, 0) output = tree.nodes.new("NodeGroupOutput") output.location = (700+(cases*200), 0) compares = [] switches = [] for i in range(cases): compares.append(tree.nodes.new("FunctionNodeCompare")) compares[i].data_type = 'INT' compares[i].hide = True compares[i].name = 'Equals '+str(i+self.start) compares[i].operation = 'EQUAL' compares[i].inputs[3].default_value = i+self.start compares[i].location = (200+((cases-i)*150), -i*250+(cases*250/2)-60) # 同步替换变量名 tree.links.new(compares[i].inputs[2], group_input.outputs[0]) switches.append(tree.nodes.new("GeometryNodeSwitch")) switches[i].location = (400+((cases-i)*150), -i*250+(cases*250/2)) if type_enum == 'VALUE': switches[i].input_type = 'FLOAT' else: switches[i].input_type = type_enum switch_type = 0 if type_enum in ('OBJECT', 'IMAGE', 'GEOMETRY', 'COLLECTION', 'TEXTURE', 'MATERIAL'): switch_type = 1 tree.links.new(switches[i].inputs[switch_type], compares[i].outputs[0]) sock = find_socket(switches[i].inputs, type_enum, "True") if sock != None: # 同步替换变量名 tree.links.new(sock, group_input.outputs[i+1]) for i in range(cases): if i == 0: sock = find_socket(switches[i].outputs, type_enum, "Output") if sock != None: tree.links.new(output.inputs[0], sock) else: sock_o = find_socket(switches[i].outputs, type_enum, "Output") sock_i = find_socket(switches[i-1].inputs, type_enum, "False") tree.links.new(sock_i, sock_o) sock_i = find_socket(switches[cases-1].inputs, type_enum, "False") # 同步替换变量名 tree.links.new(sock_i, group_input.outputs[cases+1]) group = group.nodes.new('GeometryNodeGroup') group.name = "Case Statement" group.node_tree = tree group.width = 150 return {'FINISHED'} class PickNodeOperator(bpy.types.Operator): """Pick Node Generator""" bl_idname = "node.swich_node" bl_label = "Pick Node Generator" bl_options = {'REGISTER', 'UNDO'} cases: bpy.props.IntProperty(min=0, default=6, max=25, name="# of Cases") start: bpy.props.IntProperty(default=0, name="Starting Value") type: bpy.props.EnumProperty(name="Type", items=[ ('VALUE', 'Float', "", 0), ('INT', 'Int', "", 1), ('BOOLEAN', 'Bool', "", 2), ('VECTOR', 'Vector', "", 3), ('RGBA', 'Color', "", 4), ('STRING', 'String', "", 5), ('GEOMETRY', 'Geometry', "", 6), ('OBJECT', 'Object', "", 7), ('COLLECTION', 'Collection', "", 8), ('TEXTURE', 'Texture', "", 9), ('MATERIAL', 'Material', "", 10), ('IMAGE', 'Image', "", 11) ], default='GEOMETRY') @classmethod def poll(cls, context): space = context.space_data return space.type == 'NODE_EDITOR' def execute(self, context): main(self, context) return {'FINISHED'} def menu_func(self, context): self.layout.operator(PickNodeOperator.bl_idname, text=PickNodeOperator.bl_label) def register(): bpy.utils.register_class(PickNodeOperator) bpy.types.NODE_MT_add.append(menu_func) def unregister(): bpy.utils.unregister_class(PickNodeOperator) bpy.types.NODE_MT_add.remove(menu_func) if __name__ == "__main__": register()
内容的提问来源于stack exchange,提问作者BonneJournee
相关产品推荐
相关产品推荐

