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$
1
  • $\begingroup$ hmm, anyone? I think it should be easy, I'm just missing something $\endgroup$ Oct 19, 2016 at 5:19

1 Answer 1

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.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .