Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GLTF Utilities - error - Cannot add socket to built-in node #185

Open
sweco-sekrsv opened this issue Apr 30, 2024 · 11 comments
Open

GLTF Utilities - error - Cannot add socket to built-in node #185

sweco-sekrsv opened this issue Apr 30, 2024 · 11 comments

Comments

@sweco-sekrsv
Copy link

I'm using Blender 3.6.9

I want to export the lightmaps to gltf. I get an error when clicking the "Add GLTF node" button:

Python: Traceback (most recent call last):
  File "C:\Users\sekrsv\AppData\Roaming\Blender Foundation\Blender\3.6\scripts\addons\thelightmapper\addon\operators\tlm.py", line 2056, in execute
    gltf_settings_node.inputs.new('NodeSocketFloat','Occlusion')
RuntimeError: Error: Cannot add socket to built-in node

Any ideas on how to fix that?

@sweco-sekrsv
Copy link
Author

For anyone else struggling with this. I dug into the code and did some readup on the topic. This is how I changed the TLM_AddGLTFNode in tlm.py to get it working

class TLM_AddGLTFNode(bpy.types.Operator):
    bl_idname = "tlm.add_gltf_node"
    bl_label = "Add GLTF Node"
    bl_description = "Add to GLTF node to active material and connect lightmap if present"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):

        scene = context.scene
        cycles = scene.cycles

        for obj in bpy.context.scene.objects:

            print("Iterating: " + obj.name)

            if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
                if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:

                    for slot in obj.material_slots:

                        material = slot.material

                        nodes = material.node_tree.nodes
                        # create group data
                        gltf_settings = bpy.data.node_groups.get('glTF Material Output')
                        if gltf_settings is None:
                            bpy.data.node_groups.new('glTF Material Output', 'ShaderNodeTree')

                        # add group to node tree
                        gltf_settings_node = nodes.get('glTF Material Output')
                        if gltf_settings_node is None:
                            gltf_settings_node = nodes.new('ShaderNodeGroup')
                            gltf_settings_node.name = 'glTF Material Output'
                            gltf_settings_node.node_tree = bpy.data.node_groups['glTF Material Output']

                        # create group inputs
                        if 'Occlusion' not in gltf_settings_node.node_tree.inputs:
                            gltf_settings_node.node_tree.inputs.new('NodeSocketFloat','Occlusion')                            

                        gltf_settings_node.location.y = 400

                        lightmapNode = nodes.get("TLM_Lightmap")

                        material.node_tree.links.remove(lightmapNode.outputs[0].links[0])
                        material.node_tree.links.new(lightmapNode.outputs[0], gltf_settings_node.inputs[0])
                        
                        #If the material have a node called "Lightmap_Multiplication" and it does have a input into Color2 called "Lightmap_BasecolorNode_A" remove both "Lightmap_BasecolorNode_A" and ""Lightmap_Multiplication". This needs to be done for materials that dont have a base texture but instead using a just a color
                        # Check if the "Lightmap_Multiplication" node exists
                        lightmap_multiplication_node = nodes.get("Lightmap_Multiplication")
                        if lightmap_multiplication_node is not None:
                            # Check if the "Lightmap_BasecolorNode_A" node is connected to the "Color2" input of the "Lightmap_Multiplication" node
                            color2_input = lightmap_multiplication_node.inputs.get("Color2")
                            if color2_input is not None and color2_input.is_linked:
                                lightmap_basecolor_node_a = color2_input.links[0].from_node
                                if lightmap_basecolor_node_a.name == "Lightmap_BasecolorNode_A":
                                    # Remove the "Lightmap_BasecolorNode_A" node
                                    nodes.remove(lightmap_basecolor_node_a)
                                    # Remove the "Lightmap_Multiplication" node
                                    nodes.remove(lightmap_multiplication_node)
                            else:
                                    # Remove the "Lightmap_Multiplication" node
                                    nodes.remove(lightmap_multiplication_node)


        return {'FINISHED'}

@jywarren
Copy link

I'm now seeing a different error -

File "/Users/warren/Library/Application Support/Blender/4.1/scripts/addons/thelightmapper/addon/operators/tlm.py", line 1710, in execute if 'Occlusion' not in gltf_settings_node.node_tree.inputs:
^^^^^^^^^^^^^^^^^^^^
AttributeError: 'ShaderNode Tree' object has no attribute 'inputs'

@jywarren
Copy link

Ah - noting I'm in Blender 4.1. I'm seeing some slightly different-looking naming conventions which could be related:

def lightmap_to_ao(material,lightmap_node):
nodes = material.node_tree.nodes
# -----------------------AO SETUP--------------------#
# create group data
gltf_settings = bpy.data.node_groups.get('glTF Settings')
if gltf_settings is None:
bpy.data.node_groups.new('glTF Settings', 'ShaderNodeTree')
# add group to node tree
ao_group = nodes.get('glTF Settings')
if ao_group is None:
ao_group = nodes.new('ShaderNodeGroup')
ao_group.name = 'glTF Settings'
ao_group.node_tree = bpy.data.node_groups['glTF Settings']
# create group inputs
if ao_group.inputs.get('Occlusion') is None:
ao_group.inputs.new('NodeSocketFloat','Occlusion')
# mulitply to control strength
mix_node = add_node(material,Shader_Node_Types.mix,"Adjust Lightmap")
mix_node.blend_type = "MULTIPLY"
mix_node.inputs["Fac"].default_value = 1
mix_node.inputs["Color2"].default_value = [3,3,3,1]
# position node
ao_group.location = (lightmap_node.location[0]+600,lightmap_node.location[1])
mix_node.location = (lightmap_node.location[0]+300,lightmap_node.location[1])
make_link(material,lightmap_node.outputs['Color'],mix_node.inputs['Color1'])
make_link(material,mix_node.outputs['Color'],ao_group.inputs['Occlusion'])

@sweco-sekrsv
Copy link
Author

Most likely due to Blender 4.1. I was using the latest Blender 3.6.x release

@jywarren
Copy link

Just noting via this post:

in Blender 4.0 its inputs and outputs cannot be accessed anymore like this:

input_socket = groupTree.inputs.new('NodeSocketFloat', 'Input') 

instead,

the new python API:

tree.interface.new_socket(name="My Input", in_out='INPUT')

@jywarren
Copy link

jywarren commented May 28, 2024

https://wiki.blender.org/wiki/Reference/Release_Notes/4.0/Python_API

I think it would need to be:

if 'Occlusion' not in gltf_settings_node.items_tree:
  gltf_settings_node.node_tree.interface.new_socket(name="Occlusion", in_out='INPUT')

This worked!!

@Braatwaathe
Copy link

Sorry for borderline necroing this, but I have sort of the same issue as in this thread. Started with the same issue as Sweco. Trying the addon on 4.2 as downgrading isn't an option. First of all, thanks a bunch for making the addon work with 4.0+!

I tried going through the motions sort of like this thread went, had Swecos issue, then edited in the gist change from Warren and got the second error (no inputs). I then applied the

if 'Occlusion' not in gltf_settings_node.node_tree: gltf_settings_node.node_tree.interface.new_socket(name="Occlusion", in_out='INPUT')

This did not work however, and the fix was simply to change "items_tree" to "node_tree" in the if-statement. Pasting the whole fixed class here in case someone else has the same issue and don't want to go through all the editing, saving and restarting.

class TLM_AddGLTFNode(bpy.types.Operator):
    bl_idname = "tlm.add_gltf_node"
    bl_label = "Add GLTF Node"
    bl_description = "Add to GLTF node to active material and connect lightmap if present"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):

        scene = context.scene
        cycles = scene.cycles

        for obj in bpy.context.scene.objects:

            print("Iterating: " + obj.name)

            if obj.type == 'MESH' and obj.name in bpy.context.view_layer.objects:
                if obj.TLM_ObjectProperties.tlm_mesh_lightmap_use:

                    for slot in obj.material_slots:

                        material = slot.material

                        nodes = material.node_tree.nodes
                        # create group data
                        gltf_settings = bpy.data.node_groups.get('glTF Material Output')
                        if gltf_settings is None:
                            bpy.data.node_groups.new('glTF Material Output', 'ShaderNodeTree')

                        # add group to node tree
                        gltf_settings_node = nodes.get('glTF Material Output')
                        if gltf_settings_node is None:
                            gltf_settings_node = nodes.new('ShaderNodeGroup')
                            gltf_settings_node.name = 'glTF Material Output'
                            gltf_settings_node.node_tree = bpy.data.node_groups['glTF Material Output']

                        # create group inputs
                        if 'Occlusion' not in gltf_settings_node.node_tree:
                            gltf_settings_node.node_tree.interface.new_socket(name="Occlusion", in_out='INPUT')

                        gltf_settings_node.location.y = 400

                        lightmapNode = nodes.get("TLM_Lightmap")

                        material.node_tree.links.remove(lightmapNode.outputs[0].links[0])
                        material.node_tree.links.new(lightmapNode.outputs[0], gltf_settings_node.inputs[0])

                        #If the material have a node called "Lightmap_Multiplication" and it does have a input into Color2 called "Lightmap_BasecolorNode_A" remove both "Lightmap_BasecolorNode_A" and ""Lightmap_Multiplication". This needs to be done for materials that dont have a base texture but instead using a just a color
                        # Check if the "Lightmap_Multiplication" node exists
                        lightmap_multiplication_node = nodes.get("Lightmap_Multiplication")
                        if lightmap_multiplication_node is not None:
                            # Check if the "Lightmap_BasecolorNode_A" node is connected to the "Color2" input of the "Lightmap_Multiplication" node
                            color2_input = lightmap_multiplication_node.inputs.get("Color2")
                            if color2_input is not None and color2_input.is_linked:
                                lightmap_basecolor_node_a = color2_input.links[0].from_node
                                if lightmap_basecolor_node_a.name == "Lightmap_BasecolorNode_A":
                                    # Remove the "Lightmap_BasecolorNode_A" node
                                    nodes.remove(lightmap_basecolor_node_a)
                                    # Remove the "Lightmap_Multiplication" node
                                    nodes.remove(lightmap_multiplication_node)
                            else:
                                    # Remove the "Lightmap_Multiplication" node
                                    nodes.remove(lightmap_multiplication_node)


        return {'FINISHED'}

@Naxela
Copy link
Owner

Naxela commented Jan 22, 2025

Hi @Braatwaathe

Thanks for the code, I just included it (e81fcfc) - I must admit I haven't been working much on the main branch in a while, and mostly spent time on the new 1.0 branch, so there's a fair bit of new bugs that occasionally show up from the Blender version changes

@Braatwaathe
Copy link

All credit goes to Sweco and Warren, I just changed "items" to "node"! I'd still probably vet this before pushing it though, there might be more issues (at least on 4.2)

Tried reloading blender now and now it won't export files properly again, and the gltf material output node group is empty. So yeah, at least the error messages are gone, but there is still something wrong.

@Braatwaathe
Copy link

Seems like there are some other issues indeed: the created GLTF utility node tree seems to loop. I don't know what's the intended behavior here but the node tree is a multi user group with one occlusion input for each material in the scene, but every material plugs into the topmost input. There are still no other inputs on the node, but that might be intended.

The multiply node shifting also as issues:

Python: Traceback (most recent call last):
  File "C:\Users\Redacted\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\The_Lightmapper-master\addon\operators\tlm.py", line 2102, in execute
    material.node_tree.links.remove(LM_Node.outputs[0].links[0])
                                    ^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'outputs'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants