0
$\begingroup$

I Just Have a Test Script Which Has Some Errors, As I Am Noob To Scripting I don’t Know How to Fix these errors

This script creates a Test Material and a Panel in Physics Panel and a Button is Created according to me when this Button is Pressed a Material Should be created but this is created when script is run I don’t wan’t that. This Script Creates a Node Group but I am Unable to Connect that Node -group to Material Output Node. My script is -

import bpy

#Context for Test Material
def T_M(context):
    bpy.context.scene.use_nodes = True
    tree = bpy.context.scene.node_tree 

    #removes unwanted nodes
    for node in tree.nodes:
        tree.nodes.remove(node) 

Testshader_mat = bpy.data.materials.new("TestMat")
mesh = bpy.context.object.data
mesh.materials.clear()
mesh.materials.append(Testshader_mat)
bpy.context.object.active_material.use_nodes = True
mat_name = "TestMat"
for mat in bpy.data.materials:
    if "TestMat" in mat.name:
        nodes = mat.node_tree.nodes
        for node in nodes:
            if node.type != 'OUTPUT_MATERIAL': # skip the material output node as we'll need it later
                nodes.remove(node) 



#Creating Node Group Test_Material


group = bpy.data.node_groups.new(type="ShaderNodeTree", name="Test_Material")


#Creating Group Input
group.inputs.new("NodeSocketColor", "Diffuse Color")
group.inputs.new("NodeSocketColor", "Glossy Color")
group.inputs.new("NodeSocketFloat", "Mix Factor")
group.inputs.new("NodeSocketFloat", "Glossyness")
input_node = group.nodes.new("NodeGroupInput")
input_node.location = (-800, 0)

# Creating Group Output Node
group.outputs.new("NodeSocketShader", "Diffuse Color")
group.outputs.new("NodeSocketShader", "Glossy Color")
group.outputs.new("NodeSocketShader", "Mix Output")


output_node = group.nodes.new("NodeGroupOutput")
output_node.location = (1500, 0)



#Creating Diffuse Node
Diffuse_node = group.nodes.new(type = 'ShaderNodeBsdfDiffuse')
Diffuse_node.location = (150, 100)

#Creating Glossy Node
Glossy_node = group.nodes.new(type = 'ShaderNodeBsdfGlossy')
Glossy_node.location = (300, 250)

#Creating Mix Shader Node
Mix_Shader_node = group.nodes.new(type = 'ShaderNodeMixShader')
Mix_Shader_node.location = (450,100)

# Creating Links Between Nodes
group.links.new(Diffuse_node.outputs["BSDF"], Mix_Shader_node.inputs[1])
group.links.new(Glossy_node.outputs["BSDF"], Mix_Shader_node.inputs[2])
group.links.new(input_node.outputs["Diffuse Color"], Diffuse_node.inputs[0])
group.links.new(input_node.outputs["Glossy Color"], Glossy_node.inputs[0])
group.links.new(input_node.outputs["Mix Factor"], Mix_Shader_node.inputs[0])
group.links.new(input_node.outputs["Glossyness"], Glossy_node.inputs[1])
group.links.new(output_node.inputs["Diffuse Color"], 
Diffuse_node.outputs[0])
group.links.new(output_node.inputs["Glossy Color"], Glossy_node.outputs[0])
group.links.new(output_node.inputs["Mix Output"], Mix_Shader_node.outputs[0])

# Putting Node Group to the node editor
tree = bpy.context.object.active_material.node_tree
group_node = tree.nodes.new("ShaderNodeGroup")
group_node.node_tree = group
group_node.location = (-40,300)
group_node.use_custom_color = True
group_node.color = (1,0.341,0.034)
group_node.width = (250)


ShaderNodeOutputMaterial_node = tree.nodes["Material Output"]
links = tree.links    
link = links.new(group_node.outputs[0], ShaderNodeOutputMaterial_node.inputs[1])


#operation to add Test Material Node   
class T_M(bpy.types.Operator):
    """Click this Button to Add Test Material."""
    bl_idname = "t_m.addnodes"
    bl_label = " Test Material"

    def execute(self, context):
        T_M(context)
        return {'FINISHED'}





    #operation for Panel
class LayoutPanel(bpy.types.Panel):
    bl_label = "Test Material Node"
    bl_idname = "SCENE_PT_layout"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "physics"


    def draw(self, context):
        layout = self.layout

        scene = context.scene

        layout.label(text="_______________________________________________")

        #Welcome text

        row = layout.row()
        layout.label(text=" Click on Test Material Button,")
        layout.label(text=" and the required nodes will be added to the")
        layout.label(text=" Node Editor in the form of Test Material")
        layout.label(text=" Node Group.")
        row = layout.row()
        row = layout.row()
        layout.label(text="_____________________________________________")

        #Test Material Add UI

        row = layout.row()
        row = layout.row()
        row = layout.row()

        layout.label(text=" Test Material", icon= 'MATERIAL_DATA')
        row = layout.row()
        row = layout.row()
        row = layout.row()
        layout.label(text=" This Button will Add a Material")
        layout.label(text=" For Your Object.")
        row = layout.row()
        row = layout.row()
        row = layout.row()
        row.operator("t_m.addnodes", icon= 'IMPORT')
        row = layout.row()
        layout.label(text="_______________________________________________")

    #register and unregister
def register():
    bpy.utils.register_class(T_M)
    bpy.utils.register_class(LayoutPanel)




def unregister():

    bpy.utils.unregister_class(T_M)
    bpy.utils.unregister_class(LayoutPanel)





if __name__ == "__main__":
    register()

I want that this Test_MaterialOP should Add this Material which is written above to the node editor using this -

row = layout.row() row = layout.row() row.operator("t_m.addnodes", icon= 'IMPORT') row = layout.row()

And I got This Screenshot

But when I click Test Material Button In Layout Panel A New Material Should Be Created with this But It is Not Happening It is Only Added When Script is Run,and not on clicking button

$\endgroup$
  • 3
    $\begingroup$ Hello. This is more of a learning site than a "fix-it-forme" style personal help desk. Could you rephrase your question so that it shows what the script looks like and what specific errors it throws, rather than requiring users to download and run it themselves? $\endgroup$ – Duarte Farrajota Ramos Oct 2 '19 at 15:16
  • 2
    $\begingroup$ That's a complicated script for a 'noob' - presumably it was pieced together from something else or provided as-is and not working...? It would be useful to have some history of where this has come from. An initial thought is that Python is very dependent of indentations (how much space there is to the left of lines of text). The first 'def T_M(context):' is at the same indent level as the following lines - indicating that the indentation is wrong and this would likely fail at that point, regardless of the rest. Please check the indentation with what you presumably have running. $\endgroup$ – Rich Sedman Oct 3 '19 at 7:40
  • $\begingroup$ In this script I am having error in these lines as i am not able to all the process above(creation of material etc.) - " #operation to add Test Material Node class Test_MaterialOP(bpy.types.Operator): """Click this Button to Add Test Material.""" bl_idname = "t_m.addnodes" bl_label = " Test Material" def execute(self, context): Test_MaterialOP(context) return {'FINISHED'} " **I have fixed Indentation errors $\endgroup$ – Rakesh choudhary Oct 5 '19 at 14:16
  • 1
    $\begingroup$ Please keep comments short or invite to chatroom. @Rakeshchoudhary please edit your question rather than adding code in comments. There are formatting buttons for code. $\endgroup$ – Moog Oct 5 '19 at 16:28
2
+50
$\begingroup$

There are multiple issues with your script:

  1. The indentation is incorrect. Code that belongs into your T_M function isn't indented by four spaces, which results in the code being executed even though the functions wasn't called. Similarly the functions that should be part of the class aren't indented, e.g. the execute function for Test_MaterialOP.
  2. The Test_MaterialOP calls Test_MaterialOP(context) in execute. I believe you intend to call T_M here. Creating another operator object is certainly not what you want.
  3. The Material creation in T_M is incomplete, the code wouldn't create a connection to the Material Output node.
  4. The layout code could be improved. Use layout.separator() to draw horizontal lines. Don't create empty rows that you aren't using.

These are the most obvious errors that I could spot.


The updated script still has issues. I've fixed the following problems in the script below:

  1. The entire function body has to be indented by at least four spaces (more for loops and conditionals)
  2. The operator name and the function to add the material should have different names. The operator is your button and the execute function what happens when the button is pressed. Therefore you need to call the function that creates the material in the execute function. The operator needs to be registered.
  3. The node group was connected to the volume socket for the material output. It's now connected to the shader output.
  4. Fixed for compliance with Blender's naming convention
  5. Moved the panel to the 3D View sidebar in the "Test Material" tab (open with N)
  6. Added bl_info so you can install as add-on.
  7. Moved explanatory text to the add-on's description and the operator's description. The latter will appear when you hover over the button.

bl_info = {
    "name": "Add Test Material",
    "author": "Rakesh Choudhary",
    "version": (1, 0),
    "blender": (2, 80, 0),
    "location": "View3D > Sidebar > Test Material Node",
    "description": "Click on the 'Test Material' button to add a material to your object.",
    "warning": "",
    "wiki_url": "",
    "category": "3D View"
}

import bpy


class TEST_MATERIAL_OT_add_material(bpy.types.Operator):
    bl_idname = "test_material.add_material"
    bl_label = "Add Test Material"
    bl_description = "This button will add a material to your object"

    def execute(self, context):
        self.create_material()
        return {'FINISHED'}

    def create_material(self):
        bpy.context.scene.use_nodes = True
        tree = bpy.context.scene.node_tree

        # removes unwanted nodes
        for node in tree.nodes:
            tree.nodes.remove(node)

        test_shader_mat = bpy.data.materials.new("TestMat")
        mesh = bpy.context.object.data
        mesh.materials.clear()
        mesh.materials.append(test_shader_mat)
        bpy.context.object.active_material.use_nodes = True

        for mat in bpy.data.materials:
            if "TestMat" in mat.name:
                nodes = mat.node_tree.nodes
                for node in nodes:
                    if node.type != 'OUTPUT_MATERIAL':  # skip the material output node as we'll need it later
                        nodes.remove(node)

        # Creating Node Group Test_Material
        group = bpy.data.node_groups.new(type="ShaderNodeTree", name="Test_Material")

        # Creating Group Input
        group.inputs.new("NodeSocketColor", "Diffuse Color")
        group.inputs.new("NodeSocketColor", "Glossy Color")
        group.inputs.new("NodeSocketFloat", "Mix Factor")
        group.inputs.new("NodeSocketFloat", "Glossyness")
        input_node = group.nodes.new("NodeGroupInput")
        input_node.location = (-800, 0)

        # Creating Group Output Node
        group.outputs.new("NodeSocketShader", "Diffuse Color")
        group.outputs.new("NodeSocketShader", "Glossy Color")
        group.outputs.new("NodeSocketShader", "Mix Output")

        output_node = group.nodes.new("NodeGroupOutput")
        output_node.location = (1500, 0)

        # Creating Diffuse Node
        diffuse_node = group.nodes.new(type='ShaderNodeBsdfDiffuse')
        diffuse_node.location = (150, 100)

        # Creating Glossy Node
        glossy_node = group.nodes.new(type='ShaderNodeBsdfGlossy')
        glossy_node.location = (300, 250)

        # Creating Mix Shader Node
        mix_shader_node = group.nodes.new(type='ShaderNodeMixShader')
        mix_shader_node.location = (450, 100)

        # Creating Links Between Nodes
        group.links.new(diffuse_node.outputs["BSDF"], mix_shader_node.inputs[1])
        group.links.new(glossy_node.outputs["BSDF"], mix_shader_node.inputs[2])
        group.links.new(input_node.outputs["Diffuse Color"], diffuse_node.inputs[0])
        group.links.new(input_node.outputs["Glossy Color"], glossy_node.inputs[0])
        group.links.new(input_node.outputs["Mix Factor"], mix_shader_node.inputs[0])
        group.links.new(input_node.outputs["Glossyness"], glossy_node.inputs[1])
        group.links.new(output_node.inputs["Diffuse Color"], diffuse_node.outputs[0])
        group.links.new(output_node.inputs["Glossy Color"], glossy_node.outputs[0])
        group.links.new(output_node.inputs["Mix Output"], mix_shader_node.outputs[0])

        # Putting Node Group to the node editor
        tree = bpy.context.object.active_material.node_tree
        group_node = tree.nodes.new("ShaderNodeGroup")
        group_node.node_tree = group
        group_node.location = (-40, 300)
        group_node.use_custom_color = True
        group_node.color = (1, 0.341, 0.034)
        group_node.width = 250

        shader_node_output_material_node = tree.nodes["Material Output"]
        links = tree.links
        links.new(group_node.outputs[0], shader_node_output_material_node.inputs[0])


class TEST_MATERIAL_PT_layout_panel(bpy.types.Panel):
    bl_label = "Test Material Node"
    bl_category = "Test Material"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"

    def draw(self, context):
        layout = self.layout
        layout.operator("test_material.add_material", icon='IMPORT')


classes = (TEST_MATERIAL_OT_add_material, TEST_MATERIAL_PT_layout_panel)


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


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


if __name__ == "__main__":
    register()
$\endgroup$
  • $\begingroup$ I have Fixed All The Indentation Errors and also now material creation is complete it is connected to Material output node. as in your answer i have completed point no - 1, 3, 4(Leave layout.separator for now because it is not creating any kind of error and i will improve it further) I think my problem is at point no 2 of your answer Please Explain it to me. $\endgroup$ – Rakesh choudhary Oct 6 '19 at 14:45
  • 1
    $\begingroup$ @Rakeshchoudhary If you want to call the T_M function you need to write T_M(context) instead of Test_MaterialOP(context). $\endgroup$ – Robert Gützkow Oct 6 '19 at 15:08
  • $\begingroup$ I have done as You Said You can see I have edited the question + also added screenshot I got this Material in Node editor when this script is run, I wan't that the Button "Test Material" Should be Useful and this Material should be created as Many times as I press this Button $\endgroup$ – Rakesh choudhary Oct 6 '19 at 15:45
  • 1
    $\begingroup$ @Rakeshchoudhary you shouldn't change the name of the operator, just add the function call. I've updated my answer. $\endgroup$ – Robert Gützkow Oct 6 '19 at 16:31

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.