0
$\begingroup$

I've tried to figure this out for quite some time, with no luck. If anyone can help, that would be awesome! I'm essentially trying to convert the X and Y outputs of the Separate XYZ node into a radius value using the Pythagorean Theorem. Seems like it should be easy, but I don't think I'm getting the proper values from the Inputs, nor am I setting the proper value in the outputs.

When getting the values of the inputs using default_value, they always come up 0.0 for both x and y. When setting the output, I get the error: ValueError: bpy_struct: item.attr = val: sequence expected at dimension 1, not 'float'

I based my code off of the custom_nodes.py template and from a tutorial I found online. I have no idea how correct it is and there seems to be a dearth of other samples out there for me to compare against. Any help would be much appreciated! ^_^

# Implementation of custom nodes from Python
class MyCustomTree(NodeTree):
    '''some stuff'''
    bl_idname = 'CustomTreeType'
    bl_label = 'Custom Node Tree'

# Mix-in class for all custom nodes in this tree type.
# Defines a poll function to enable instantiation.
class MyCustomTreeNode:
    @classmethod
    def poll(cls, ntree):
        return ntree.bl_idname == 'ShaderNodeTree'

# Derived from the Node base type.
class XYToRadiusNode(Node, MyCustomTreeNode):
    # === Basics ===
    # Description string
    '''XY coordinates to radius'''
    # Optional identifier string. If not explicitly defined, the python class name is used.
    bl_idname = 'XYToRadius'
    # Label for nice name display
    bl_label = 'XY To Radius'


    def update_value(self, context):
        print("updatevalue");
        inX = self.inputs["X"]
        inY = self.inputs["Y"]
        if inX.is_linked and inX.links[0].is_valid and inY.is_linked and inY.links[0].is_valid:
            x_val = inX.links[0].from_socket.default_value
            y_val = inY.links[0].from_socket.default_value

            self.radius = math.sqrt(pow(x_val, 2.) + pow(y_val, 2.))
            self.outputs["Radius"].default_value = self.radius 
        else:
            self.outputs["Radius"].default_value = 0.0
            self.radius = 0.0

    radius = 0.0

    # === 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):
        print("init")
        self.inputs.new('NodeSocketFloat', "X")
        self.inputs.new('NodeSocketFloat', "Y")

        self.outputs.new('NodeSocketFloat', "Radius")

    # Additional buttons displayed on the node.
    def draw_buttons(self, context, layout):
        return

    # Optional: custom label
    # Explicit user label overrides this, but here we can define a label dynamically
    def draw_label(self):
        return "XY to Radius"

    def update(self):
        print("update")
        try:
            out = self.outputs["Radius"]
            inY = self.inputs["Y"]
            inX = self.inputs["X"]
            can_continue = True
        except:
            can_continue = False
        if can_continue:
            if out.is_linked and inX.is_linked and inY.is_linked:
                for o in out.links:
                    if o.is_valid:
                        self.update_value(None)
                        print(self.radius)
                        o.to_socket.default_value = self.outputs["Radius"].default_value

### Node Categories ###
# Node categories are a python system for automatically
# extending the Add menu, toolbar panels and search operator.
# For more examples see release/scripts/startup/nodeitems_builtins.py

import nodeitems_utils
from nodeitems_utils import NodeCategory, NodeItem


# our own base class with an appropriate poll function,
# so the categories only show up in our own tree type
class MyNodeCategory(NodeCategory):
    @classmethod
    def poll(cls, context):
        return context.space_data.tree_type == 'ShaderNodeTree'

# all categories in a list
node_categories = [
    # identifier, label, items list
    MyNodeCategory("MY_NODES", "My Nodes", items=[
        # our basic node
        NodeItem("XYToRadius"),
        ])]


def register():
    bpy.utils.register_class(XYToRadiusNode)
    nodeitems_utils.register_node_categories("MY_NODES", node_categories)


def unregister():
    nodeitems_utils.unregister_node_categories("MY_NODES")
    bpy.utils.unregister_class(XYToRadiusNode)

def pre_frame_change(scene):
    if scene.render.engine == 'CYCLES':
        for m in bpy.data.materials:
            if m.node_tree != None:
                for n in m.node_tree.nodes:
                    if n.bl_idname == 'XYToRadius':
                        print(n.bl_idname)
                        v = n.radius
                        n.radius = v

if __name__ == "__main__":
    register()
    bpy.app.handlers.frame_change_pre.append(pre_frame_change)
$\endgroup$
  • $\begingroup$ hmm, anyone? I think it should be easy, I'm just missing something $\endgroup$ – Noah Duncan Oct 19 '16 at 5:19
0
$\begingroup$

I ran into exactly the same problem when setting radiuses of skin modifier vertexes. If you interrogate blender in console, typing your_mesh.radius<Ctrl-space>, it will tell you it is expecting a 2-element list. Indeed, assigning a tuple of floats shows that these 2 floats are 2 radiuses along 2 perpendicular axes (think of X and Y, while Z is the direction to the next vertex).

So x.radius = (1.0, 1.0) will make a round skin vertex, while x.radius = (1.0, 2.0) will make it elliptical, etc.

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.