24
$\begingroup$

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

$\endgroup$
0

4 Answers 4

32
$\begingroup$

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)
$\endgroup$
2
  • 3
    $\begingroup$ For an example on using nodes from python, heres a script the FBX importer uses to setup a nodetree: git.blender.org/gitweb/gitweb.cgi/blender-addons.git/blob_plain/… $\endgroup$ Commented Dec 19, 2013 at 12:36
  • 3
    $\begingroup$ +1 for the # Enable 'Use nodes': tip! I was so confused why I can't refer to the node_tree attribute. $\endgroup$ Commented Dec 26, 2016 at 22:45
24
$\begingroup$

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
$\endgroup$
2
  • 1
    $\begingroup$ 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. $\endgroup$ Commented Dec 27, 2016 at 2:46
  • $\begingroup$ Color can be set analog to Strength: emission.inputs['Color'].default_value = (0,1,0,1) # green RGBA $\endgroup$ Commented Dec 26, 2019 at 12:55
3
$\begingroup$

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
$\endgroup$
1
$\begingroup$

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))
$\endgroup$
2
  • 1
    $\begingroup$ mat = materials.get(materials.new(mat_name).name) $\endgroup$ Commented Jan 28, 2017 at 23:10
  • $\begingroup$ cool if that works :) $\endgroup$ Commented Jan 29, 2017 at 15:46

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.