I want to create a custom pynode that reads the object properties (position, rotation, scale ...) of the current object on what the material with the custom pynode is applied to and use these values for the shader itself. E.g. If the position of the object changes, then this should affect the color of the shader.
I've used this base setup from Atom and tried to draw the object position as float value into the node:
#NOTE: Run this code first then use SHIFT-A, below, to add Custom Float node type.
import bpy
from bpy.types import NodeTree, Node, NodeSocket
# Implementation of custom nodes from Python
# Derived from the NodeTree base type, similar to Menu, Operator, Panel, etc.
class MyCustomTree(NodeTree):
bl_idname = 'CustomTreeType'
bl_label = 'Custom Node Tree'
# Defines a poll function to enable filtering for various node tree types.
class MyCustomTreeNode :
@classmethod
def poll(cls, ntree):
b = False
# Make your node appear in different node trees by adding their bl_idname type here.
if ntree.bl_idname == 'ShaderNodeTree': b = True
return b
# Derived from the Node base type.
class MyCustomNode(Node, MyCustomTreeNode):
'''A custom node'''
bl_idname = 'CustomNodeType'
bl_label = 'Custom Float'
bl_icon = 'INFO'
def update_value(self, context):
self.outputs["Float"].default_value = self.some_value
self.outputs["Color"].default_value = self.some_color_value
self.update ()
# float value
some_value = bpy.props.FloatProperty(default=0.0, update = update_value)
# color value
some_color_value = bpy.props.FloatVectorProperty(
name = "Color",
subtype = "COLOR",
size = 4,
min = 0.0,
max = 1.0,
default = (0.75,0.0,0.8,1.0)
)
def init(self, context):
self.outputs.new('NodeSocketFloat', "Float")
self.outputs.new('NodeSocketColor', 'Color')
self.outputs["Float"].default_value = self.some_value
self.outputs["Color"].default_value = self.some_color_value
def update(self):
#Review linked outputs.
try:
out = self.outputs["Float"]
out = self.outputs["Color"]
print (out_clr)
can_continue = True
except:
can_continue = False
if can_continue:
if out.is_linked:
# I am an ouput node that is linked, try to update my link.
for o in out.links:
if o.is_valid:
o.to_socket.node.inputs[o.to_socket.name].default_value = self.outputs["Float"].some_value #self.some_value
for o in out_clr.links:
o.to_socket.node.inputs[o.to_socket.name].default_value = self.outputs["Color"].some_color_value #self.some_value
# Additional buttons displayed on the node.
def draw_buttons(self, context, layout):
layout.prop(self, "some_value",text = '')
layout.prop(self, "some_color_value",text = 'Color')
# Optional: custom label
# Explicit user label overrides this, but here we can define a label dynamically.
def draw_label(self):
return "My Float"
### Node Categories ###
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 target tree type
class MyNodeCategory(NodeCategory):
@classmethod
def poll(cls, context):
b = False
# Make your node appear in different node trees by adding their bl_idname type here.
if context.space_data.tree_type == 'ShaderNodeTree': b = True
return b
# all categories in a list
node_categories = [
# identifier, label, items list
MyNodeCategory("SOMENODES", "Custom Float", items=[
NodeItem("CustomNodeType"),
]),
]
def register():
bpy.utils.register_class(MyCustomNode)
nodeitems_utils.register_node_categories("CUSTOM_NODES", node_categories)
def unregister():
nodeitems_utils.unregister_node_categories("CUSTOM_NODES")
bpy.utils.unregister_class(MyCustomNode)
def pre_frame_change(scene):
if scene.render.engine == 'CYCLES':
# Scan materials to see if I have a custom node within any of the trees.
for obj in bpy.data.objects:
if obj.type == 'MESH':
for m in obj.data.materials:
if m.node_tree != None:
for n in m.node_tree.nodes:
if n.bl_idname == 'CustomNodeType':
print ("THIS IS THE OBJECT" + obj.name)
print(n.bl_idname)
# One of our custom nodes, let's update it.
# When we set the value that will trigger an update inside the node.
# Even if we change it to the same value it was.
v = n.some_color_value
print (v)
n.some_color_value = v
print (n)
if __name__ == "__main__":
register()
bpy.app.handlers.frame_change_pre.append(pre_frame_change)
But unfortunately I don't really understand the concept of pynodes to accessing the properties of the scene object and update it for every frame if the values are animated.
How can I get object properties to use it for the shader itself?