Target Nodes Inside A Group

As of 3.2.1, Blender ITP (Image Texture Properties) is Slightly Broken

This add-on is an alternate way to manipulate one or more Image Texture nodes. It creates a sidebar panel that exposed the Interpolation, Projection, and Extension properties.

ITP Panel

I have two outstanding issues I haven’t been able to figure out.

Rather than post to whole file to this thread, here’s a link to the .py on GitHub, and I’ll just quote snippets that I think are relevant.

1.) If image nodes are inside of a group, the sidebar panel is blank.

When an image node is selected, the above panel is displayed. But if no image node is selected, the panel shows this:

ITP Panel Null

I’m using context to detect:

node = context.space_data.node_tree.nodes.active

However when an image node inside of a group is selected, the panel shows the Null state.

I’d love to be able to affect image nodes inside of a group.

2.) As of Blender 3.2.1, the BOX projection Blend Value property does not show up in sidebar panel.

In Blender 3.1.2, when an image node’s Projection is set to BOX, the panel shows the Blend Value under the buttons:

ITP Panel 3.1.2

But starting in Blender 3.2, the field doesn’t appear, and I get this error:

rna_uiItemR: property not found: MySettings.blend_val
node_image_texture_properties.py:112

Line 112 is inside the panel’s draw function

row.prop(mytool, "blend_val")

my_tool is defined earlier in the same draw function:

mytool = scene.my_tool

and registed like this:

bpy.types.Scene.my_tool = bpy.props.PointerProperty(type = MyProperties)

And this is how blend_val is defined at the top of the file:

def whenUpdate( self, context ):
    nodes, links = get_nodes_links(context)
    for node in nodes:
        if node.select == True:
            if node.type == 'TEX_IMAGE':
                node.projection_blend = self.blend_val

class MyProperties(bpy.types.PropertyGroup):
    blend_val : bpy.props.FloatProperty(name = "Blend:", min = 0, max = 1, update = whenUpdate)

So Blender community, that’s the gist of it. Once again I am asking for your support.

If anyone has suggestions, I’d be grateful.

I’m not in a position to test this out on anything beyond Blender 3.1.5 at the moment, but just scanning through the code I find this part to be the most interesting/odd. what happens if you print(type(context.scene.my_tool))? it should be MyProperties, but the exception seems to indicate it’s MySettings (which so far as I can tell doesn’t even exist in your code at all)? Is it possible that you have another addon that is registering scene.my_tool afterward (and subsequently overwriting) your custom property?

I would try renaming my_tool to something more specific to your addon and see if that doesn’t help.

2 Likes

It works on my version of 3.2.1. Please make sure you’re using this exact same script.

To get the active node in a node group recursively inception style add these 2 lines in RN_PT_NodeITPanel in the draw method :

while node and node.type == "GROUP": node = node.node_tree.nodes.active

 def draw(self, context):
        if context.active_node is not None:
            layout = self.layout
            scene = context.scene
            mytool = scene.my_tool
            row = layout.row()
            node = context.space_data.node_tree.nodes.active
            while node and node.type == "GROUP":
                node = node.node_tree.nodes.active
            if node and node.type == 'TEX_IMAGE':

                row = layout.row(align=True)
                row.label(text="Interpolation:")

                row = layout.row(align=True)
                row.operator('node.button_linear')
                row.operator('node.button_closest')

                row = layout.row(align=True)
                row.operator('node.button_cubic')
                row.operator('node.button_smart')
etc.

To get all the image textures recursively in a node tree you can use :

    image_texture_nodes = []
    node_groups = [n for n in context.space_data.node_tree.nodes if n.type == "GROUP"]
    while node_groups:
        node_group = node_groups.pop(0)
        node_groups.extend([n for n in node_group.node_tree.nodes if n.type == "GROUP"])
        image_texture_nodes.extend([n for n in node_group.node_tree.nodes if n.type == "TEX_IMAGE"])
    print(image_texture_nodes)

Also protip : Since you’re using git versioning, you don’t need this kind of modification history :

"""
VERSION HISTORY
1.0 – 18/03/22
    – Create Addon
"""

You can use commit messages for this.

3 Likes

Thank You!

Yes, it was a simple matter of changing the var name.

I was also getting an error when I disabled the add-on, so I commented out the var name in unregister, and now everything is fine.

Here’s the new code:

def register():
    for c in classes:
        bpy.utils.register_class(c)
        bpy.types.Scene.blend_val_tool = bpy.props.PointerProperty(type = BlendValProperty)

def unregister():
    for c in classes:
        bpy.utils.unregister_class(c)
        # del bpy.types.Scene.blend_val_tool

It’s noob misses like this that remind me I need to learn the basics of debugging Python for Blender…

Anyway, thanks again for your help! :+1:

Thank You!

I added

while node and node.type == "GROUP":
  node = node.node_tree.nodes.active

and all is working!

Can I ask if you know where documentation of node.type = "GROUP" can be found? I found GROUP as a bl_icon option on the Node(bpy_struct) page, but beyond that, I’m stumped.

Thanks for the “Recursively Select Image Nodes” snippet. I’ve appended it to the bottom of the file, but commented out for now. I want to be able to pick and choose which image nodes get affected, but an “Affect All” checkbox might be a nice addition.

And per your final note, I moved the version history to a CHANGELOG file.

Once again, thank you for your help!

Here’s a link to the updated release: Blender ITP 1.0.1

Happy to help !

Hehe unfortunately AFAIK the only way to retrieve this information from all nodes is to parse all possible nodes and print their type. This might help https://blender.stackexchange.com/a/79981/86891

1 Like

the problem is that blend_val_tool is not a class, but it’s inside ‘for’ declaration.

def register():
    for c in classes:
        bpy.utils.register_class(c)

    bpy.types.Scene.blend_val_tool = bpy.props.PointerProperty(type = BlendValProperty)

def unregister():
    for c in classes:
        bpy.utils.unregister_class(c)

    del bpy.types.Scene.blend_val_tool
2 Likes

Thank You!

The plugin now recognizes Nodes inside groups.

Here’s a link to the updated release: Blender ITP 1.0.4

1 Like

Glad to know you solved that secondary issue…