I understand your problem.
When you load your script as an addon, it reads the scripts when loading blender. Thus the scripts register the the bpy.context.active_object = the active object when the addon is loader. Thus it does not point to the actual bpy.context.active_object when you run the operator.
For instance your makeLink(var1, var2, var3, var4):
reference the link object which is the link of the node_three of the material of the active object when the addons was enable. Which may be not the one you want to modify. I hope your understand your mistake.
To solve your problem, you need to modify every function you made to be context sensitive. For instance, your main function should take as argument the context variable of the operator. (BTW the main class should'nt be a class but a functon, i.e. def main(...)
instead of class main()
).
Then in the main function you should now declare the the mat_name, the node_tree, the links,... (everything that you declare at the beginning of your script)
def main(context):
mat_name = context.active_object.active_material.name
mat = (bpy.data.materials.get(mat_name) or bpy.data.materials.new(mat_name))
mat.use_nodes = True
nt = mat.node_tree
nodes = nt.nodes
links = nt.links
while (nodes): nodes.remove(nodes[0])
createNodes(nodes)
...
But then you also need to modify every function you have since the need to point to the correct variable. For instance the make link should be:
def makeLink(links, var1, var2, var3, var4):
"""
Creates a link between a Material Node's output,
and another Material Node's input.
args follow the order: Output Node Name, Socket Name, Input Node Name, Socket Name
"""
links.new(var1.inputs[var2], var3.outputs[var4])
def createNodes(nodes):
link = nodes.link;
output = nodes.new("ShaderNodeOutputMaterial")
principled = nodes.new ("ShaderNodeBsdfPrincipled")
mapping = nodes.new("ShaderNodeMapping")
texCoord = nodes.new("ShaderNodeTexCoord")
colorMap = nodes.new("ShaderNodeTexImage")
normalMap = nodes.new("ShaderNodeTexImage")
roughMap = nodes.new("ShaderNodeTexImage")#.color_space = 'NONE'
mainTexCoord = [ node for node in mat.node_tree.nodes if node.bl_idname=="ShaderNodeTexCoord"]
# python list comprehension filters the list of nodes down to the ones that match the right bl_idname
texCoordinateNode = mainTexCoord[0]
#Image Texture Node Image
colorMap.image = bpy.data.images.load(image_path)
normalMap.image = bpy.data.images.load(image_path2)
roughMap.image = bpy.data.images.load(image_path2)
makeLink(output, 'Surface', principled, 'BSDF')
makeLink(mapping, 'Vector', texCoordinateNode, 'UV')
makeLink(principled, 'Base Color', colorMap, 'Color')
makeLink(colorMap, 'Vector', mapping, 'Vector')
makeLink(principled, 'Normal', normalMap, 'Color')
makeLink(normalMap, 'Vector', mapping, 'Vector')
makeLink(principled, "Metallic", roughMap, 'Color')
makeLink(roughMap, 'Vector', mapping, 'Vector')
Then the operator should be like this:
class QuickLayout(bpy.types.Operator):
"""Tooltip"""
bl_idname = "myops.quick_layout"
bl_label = "Quick PBR Layout"
def execute(self, context):
main(context)
self.report({'INFO'}, "Layout Complete!")
return {'FINISHED'}
I hope you understood where the problem was.
Cheers
bpy.context
? Notice that your question is very vague and even the title does not really match the body. Also can you please post all relevant code here? $\endgroup$operator_node.py
template that's shipped with blender to get your script converted into an addon (Templates > Python > Operator Node) and store your properties in one PropertyGroup, that's good practice and well organized (my answer to your questions). $\endgroup$