我正在尝试编写可以创建自定义节点的blender插件,我们可以将它们作为普通的blender构建节点来操作,特别是将它们组合在一起,在我的选项中它是一个非常导入的函数,但现在代码可以添加自定义节点,但分组仍然不起作用,所以任何提示?
#
# architect.py -- the blender addon
#
import bpy
import nodeitems_utils
from nodeitems_utils import NodeCategory, NodeItem, NodeItemCustom
from bpy.types import NodeTree, ShaderNodeTree, Node, NodeGroup, NodeCustomGroup, NodeSocket
bl_info = {
"name": "Architect",
"author": "Lei Liu",
"category": "Node"}
class ArchitectEngine(bpy.types.RenderEngine):
bl_idname = 'ARCHITECT_RENDER'
bl_label = "Architect"
bl_use_preview = False
bl_use_shading_nodes = False
bl_use_exclude_layers = False
bl_use_save_buffers = False
draw_callbacks = {}
def __init__(self):
self.session = None
pass
def __del__(self):
pass
# main scene render
def update(self, data, scene):
pass
def render(self, scene):
pass
class ArchitectNodeTree(ShaderNodeTree):
bl_idname = 'ArchitectNodeTree'
bl_label = 'Architect Node Tree'
bl_icon = 'NODETREE'
nodetypes = {}
pass
@classmethod
def poll(cls, context):
return context.scene.render.engine == 'ARCHITECT_RENDER'
class ArchitectNodeGroup(NodeCustomGroup):
bl_idname = 'ArchitectNodeGroup'
bl_label = 'Architect Node Group'
node_tree = ArchitectNodeTree
@classmethod
def poll(cls, context):
return context.scene.render.engine == 'ARCHITECT_RENDER'
# Custom socket type
class ArchitectSocket(NodeSocket):
# Description string
'''Architect node socket type'''
# Optional identifier string. If not explicitly defined, the python class name is used.
bl_idname = 'ArchitectSocketType'
# Label for nice name display
bl_label = 'Architect Node Socket'
# Enum items list
my_items = [
("DOWN", "Down", "Where your feet are"),
("UP", "Up", "Where your head should be"),
("LEFT", "Left", "Not right"),
("RIGHT", "Right", "Not left")
]
myEnumProperty = bpy.props.EnumProperty(name="Direction", description="Just an example", items=my_items, default='UP')
# Optional function for drawing the socket input value
def draw(self, context, layout, node, text):
if self.is_output or self.is_linked:
layout.label(text)
else:
layout.prop(self, "myEnumProperty", text=text)
# Socket color
def draw_color(self, context, node):
return (1.0, 0.4, 0.216, 0.5)
class ArchitectTreeNode:
@classmethod
def poll(cls, ntree):
return ntree.bl_idname == 'ArchitectNodeTree'
class DemoNode(Node, ArchitectTreeNode):
bl_idname = 'DemoNodeType'
bl_label = 'Demo Node'
bl_icon = 'SOUND'
typename = 'DemoNodeType'
# === Custom Properties ===
# These work just like custom properties in ID data blocks
# Extensive information can be found under
# http://wiki.blender.org/index.php/Doc:2.6/Manual/Extensions/Python/Properties
myStringProperty = bpy.props.StringProperty()
myFloatProperty = bpy.props.FloatProperty(default=3.1415926)
# === Optional Functions ===
# Initialization function, called when a new node is created.
# This is the most common place to create the sockets for a node, as shown below.
# NOTE: this is not the same as the standard __init__ function in Python, which is
# a purely internal Python method and unknown to the node system!
def init(self, context):
self.inputs.new('ArchitectSocketType', "Hello")
self.inputs.new('NodeSocketFloat', "World")
self.inputs.new('NodeSocketVector', "!")
self.outputs.new('NodeSocketColor', "How")
self.outputs.new('NodeSocketColor', "are")
self.outputs.new('NodeSocketFloat', "you")
# Copy function to initialize a copied node from an existing one.
def copy(self, node):
print("Copying from node ", node)
# Free function to clean up on removal.
def free(self):
print("Removing node ", self, ", Goodbye!")
# Additional buttons displayed on the node.
def draw_buttons(self, context, layout):
layout.label("Node settings")
layout.prop(self, "myFloatProperty")
# Detail buttons in the sidebar.
# If this function is not defined, the draw_buttons function is used instead
def draw_buttons_ext(self, context, layout):
layout.prop(self, "myFloatProperty")
# myStringProperty button will only be visible in the sidebar
layout.prop(self, "myStringProperty")
# Optional: custom label
# Explicit user label overrides this, but here we can define a label dynamically
def draw_label(self):
return "I am a custom node"
class ArchitectNodeCategory(NodeCategory):
@classmethod
def poll(cls, context):
return (context.space_data.tree_type == 'ArchitectNodeTree')
# menu entry for node group tools
def group_tools_draw(self, layout, context):
layout.operator("node.group_make")
layout.operator("node.group_ungroup")
layout.separator()
# maps node tree type to group node type
node_tree_group_type = {
'CompositorNodeTree': 'CompositorNodeGroup',
'ShaderNodeTree': 'ShaderNodeGroup',
'TextureNodeTree': 'TextureNodeGroup',
'ArchitectNodeTree': 'ArchitectNodeGroup',
}
# generic node group items generator for shader, compositor and texture node groups
def node_group_items(context):
if context is None:
return
space = context.space_data
if not space:
return
ntree = space.edit_tree
if not ntree:
return
yield NodeItemCustom(draw=group_tools_draw)
def contains_group(nodetree, group):
if nodetree == group:
return True
else:
for node in nodetree.nodes:
if node.bl_idname in node_tree_group_type.values() and node.node_tree is not None:
if contains_group(node.node_tree, group):
return True
return False
for group in context.blend_data.node_groups:
if group.bl_idname != ntree.bl_idname:
continue
# filter out recursive groups
if contains_group(group, ntree):
continue
yield NodeItem(node_tree_group_type[group.bl_idname],
group.name,
{"node_tree": "bpy.data.node_groups[%r]" % group.name})
# only show input/output nodes inside node groups
def group_input_output_item_poll(context):
return False
architect_node_categories = [
ArchitectNodeCategory("ARCH_DEMO", "Demo", items=[
NodeItem("DemoNodeType"),
]),
ArchitectNodeCategory("ARCH_INPUT", "Input", items=[
NodeItem("TextureNodeCurveTime"),
NodeItem("TextureNodeCoordinates"),
NodeItem("TextureNodeTexture"),
NodeItem("TextureNodeImage"),
NodeItem("NodeGroupInput", poll=group_input_output_item_poll),
]),
ArchitectNodeCategory("ARCH_OUTPUT", "Output", items=[
NodeItem("NodeGroupOutput", poll=group_input_output_item_poll),
]),
ArchitectNodeCategory("ARCH_GROUP", "Group", items=node_group_items),
ArchitectNodeCategory("ARCH_LAYOUT", "Layout", items=[
NodeItem("NodeFrame"),
NodeItem("NodeReroute"),
]),
]
def register():
bpy.utils.register_class(ArchitectNodeTree)
bpy.utils.register_class(ArchitectNodeGroup)
bpy.utils.register_class(DemoNode)
nodeitems_utils.register_node_categories('ARCHITECT', architect_node_categories)
bpy.utils.register_module(__name__)
pass
def unregister():
nodeitems_utils.unregister_node_categories('ARCHITECT')
bpy.utils.unregister_class(ArchitectNodeGroup)
bpy.utils.unregister_class(ArchitectNodeTree)
bpy.utils.unregister_class(DemoNode)
bpy.utils.unregister_module(__name__)
pass
if __name__ == "__main__":
register()