24

I have edited a script that creates some nodes, but the only problem is, it always created a new material. I want it to either add the nodes on the existing material, or a pre-defined material. Here is the script base I am using.

http://blenderscripting.blogspot.com.es/2013/06/automatic-colour-ramped-shader-from.html

Thanks for the help in advance! :D

gandalf3
  • 157,169
  • 58
  • 601
  • 1,133
rioforce
  • 2,042
  • 2
  • 22
  • 34

4 Answers4

30

You can get the material node tree from bpy.data.materials['MyMaterial'].node_tree

Then add the nodes with node_tree.nodes.new()

For example, to add a diffuse shader node to MyMaterial and create MyMaterial if it doesn't exist:

import bpy
mat_name = "MyMaterial"
# Test if material exists
# If it does not exist, create it:
mat = (bpy.data.materials.get(mat_name) or 
       bpy.data.materials.new(mat_name))

# Enable 'Use nodes':
mat.use_nodes = True
nodes = mat.node_tree.nodes

# Add a diffuse shader and set its location:    
node = nodes.new('ShaderNodeBsdfDiffuse')
node.location = (100,100)
pink vertex
  • 9,896
  • 1
  • 25
  • 44
gandalf3
  • 157,169
  • 58
  • 601
  • 1,133
  • 3
    For an example on using nodes from python, heres a script the FBX importer uses to setup a nodetree: http://git.blender.org/gitweb/gitweb.cgi/blender-addons.git/blob_plain/HEAD:/io_scene_fbx/cycles_shader_compat.py – ideasman42 Dec 19 '13 at 12:36
  • 2
    +1 for the # Enable 'Use nodes': tip! I was so confused why I can't refer to the node_tree attribute. – Sibbs Gambling Dec 26 '16 at 22:45
24

The answer provided is only partially helpful. Or it is outdated in 2.7

Yes you have to add the nodes (use_nodes = True). However the default material is the Diffuse BSDF. So if you want to use this, fine, you're done. But to change the shader being used:

  1. Remove the shader in place (Diffuse BSDF, otherwise the second element in the material.node_tree.nodes.values() list. This is sort of optional, as it can also stay in place, but it's just not tidy and confusing to leave it there.
  2. Create a new shader node. e.g. material.node_tree.nodes.new('ShaderNodeEmission')
  3. Update the link to the Material Output node. material.node_tree.links.new(mat.inputs[0], node.outputs[0])

Here an example I made I use quite often: a Mesh Light

    def create_light():
        """
        Add a mesh light for cycles
        """

        # Add new plane
        bpy.ops.mesh.primitive_plane_add(location=(15, -5, 5))
        plane = bpy.context.active_object
        plane.name = 'Light Plane'
        plane.scale = mathutils.Vector((4, 4, 4))
        # tilt
        plane.rotation_euler.rotate_axis('Y', radians(40))

        # Create a new material
        material = bpy.data.materials.new(name="Plane Light Emission Shader")
        material.use_nodes = True

        # Remove default
        material.node_tree.nodes.remove(material.node_tree.nodes.get('Diffuse BSDF'))
        material_output = material.node_tree.nodes.get('Material Output')
        emission = material.node_tree.nodes.new('ShaderNodeEmission')
        emission.inputs['Strength'].default_value = 5.0

        # link emission shader to material
        material.node_tree.links.new(material_output.inputs[0], emission.outputs[0])

        # set activer material to your new material
        plane.active_material = material
fritzvd
  • 341
  • 2
  • 3
  • 1
    Your this code snippet is very helpful Sir. Thank you so much! Took me a while to figure out that link. Then I remember I saw your answer before. – Sibbs Gambling Dec 27 '16 at 02:46
  • Color can be set analog to Strength: emission.inputs['Color'].default_value = (0,1,0,1) # green RGBA – jakob.j Dec 26 '19 at 12:55
3

now at first you have principled BSDF. a variation with a diffuse node on active object

import bpy

# Create a new material
material = bpy.data.materials.new(name="Diffuse")
material.use_nodes = True

# Remove default
material.node_tree.nodes.remove(material.node_tree.nodes.get('Principled BSDF')) #title of the existing node when materials.new
material_output = material.node_tree.nodes.get('Material Output')
diffuse = material.node_tree.nodes.new('ShaderNodeBsdfDiffuse')    #name of diffuse BSDF when added with shift+A


diffuse.inputs['Color'].default_value = (1, 0, 1, 1) #last value alpha

# link diffuse shader to material
material.node_tree.links.new(material_output.inputs[0], diffuse.outputs[0])

# set activer material to your new material
bpy.context.object.active_material = material
1

Another way to do this is. It picks up a material if it exists, else creates a new one with that name.

import bpy

mat_name = "MyMaterial"
materials = bpy.data.materials

# if .get returns None, the assignment comes from the right of the 'or'
mat = materials.get(mat_name) or materials.new(mat_name)   # *** see comment
mat.use_nodes = True
nodes = mat.node_tree.nodes

# Add a diffuse shader and set its location:    
node = nodes.new('ShaderNodeBsdfDiffuse')
node.location = (100,100)

I expected this to work, but it doesn't.

mat = materials.get(mat_name, materials.new(mat_name))
zeffii
  • 39,634
  • 9
  • 103
  • 186