2016-08-16 3 views
0

私はカスタムノードを作成することができるブレンダーアドオンを作成しようとしています。それらを通常のブレンダーノードとして扱うことができます。特に私のオプションでは非常にインポート機能ですが、ノードはまだグループ化されていないので、ヒントはありますか?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() 

答えて

1

カスタムノードツリー内のノードグループの作成と編集は、カスタムノードツリーを定義するコードによって実装する必要があります。

カスタムノードグループを実装する例については、this questionを参照してください。

関連する問題