Blender 2.92 python Object Creation and Material issue

Hi,

This is my first attempt on this site. I’ll have to see whether I can find how to show code.

I am totally new to blender python, I DID peruse the IDE documentation, and I still can’t resolve two issues:

I create a reference object (a very thin plane that is supposed to be a line).

Then I duplicate the reference line, called LineRef in the code, a number of time (after moving it to (0, 0)), and each new copy is placed on the periphery of an imaginary circle, equidistant from the others ,and rotated so that they form a polygon inscribed in the circle. They are Line_0_0, Line_0_1, and so on.

Then, I give them materials.

The two issues I have are:

  1. When I am done creating all the “lines”, the last line I created and the reference line seem to be swapped. I don’t know what I did wrong.

  2. When I look at each line’s material, I can see that the original BSDF node is still there. How can I get rid of it?

Here is the code

import bpy
from math import sin, cos, tau, sqrt
import os

os.system("cls")

showDebug = False # for debug: show points and line lengths arrays
showColMats = False # for debug: show colors and materials
emission_mat = []
lineNr = 0
mats = bpy.data.materials
points = []
numPoints = 7 # The number of points to be distributed equidistantly on the circumference of the circle of radius defined below
radius = 100 # The radius of the circle the points will sit on
# The consecutive values, from index 1, of the array below have the length of a side from a point to a point index away from it
sidesLen = []
sidesLen.append(0) # Array of sides lengths [0] has 0, see note 3 lines above

colors_and_strengths = [((1, 1, 1, 1), 50, "white"),
                      ((1, 0, 0, 1), 50, "red"),
                      ((0, 1, 0, 1), 50, "green"), 
                      ((0, 0, 1, 1), 50, "blue"),
                      ((1, 1, 0, 1), 50, "yellow"),
                      ((1, 0, 1, 1), 50, "purple"),
                      ((.008, .008, .008, 1), 50, "gray")  ]
##### REMOVE OLD LINES FUNCTION
def removeOldLines():
    objs = bpy.data.objects
    for obj in objs:
        if obj.name != 'Camera' and obj.name != 'Arrow' and obj.name != 'Light':
            bpy.data.objects.remove(obj, do_unlink=True)
##### END OF REMOVE OLD LINES FUNCTION



##### START OF PURGEOLDMATERIALS FUNCTION, FROM https://blenderartists.org/t/deleting-all-materials-in-script/594160/2
def purgeOldMaterials():
    for mat in mats:
        mats.remove(bpy.data.materials[0])
##### END OF PURGEOLDMATERIALS FUNCTION



##### START OF POPULATEPOINTSANDLINELENGTHS FUNCTION
def populatePointsAndLineLengths():
    global radius
    global sideLen
    
    for i in range(numPoints):
        points.append((round(radius * cos(i * tau/numPoints)), round(radius * sin(i * tau/numPoints)), 0))
    if showDebug == True:
        for i in range(len(points)):
            print("I have points[", str(i), "]:", points[i])
       
    # Build sidesLen array for EVEN numPoints
    if numPoints % 2 == 0:
        numPointsOver2 = int (numPoints/2)

        # Fill from 0 to numPoints/2 excluded
        for i in range(1, numPointsOver2):
            sidesLen.append(round(sqrt((points[i][0] - points[0][0]) * (points[i][0] - points[0][0]) + (points[i][1] - points[0][1]) * (points[i][1] - points[0][1]))))
            
        # Fill numPoints/2, the lone longest segment
        sidesLen.append(round(sqrt((points[numPointsOver2][0] - points[0][0]) * (points[numPointsOver2][0] - points[0][0]) + (points[numPointsOver2][1] - points[0][1]) * (points[numPointsOver2][1] - points[0][1]))))
       
        # Fill numPoints/2 + 1 to numPoints - 1
        for i in range(numPointsOver2 + 1, numPoints - 0):
            sidesLen.append(sidesLen[numPoints - i]) 
    # END OF BUILD SIDES LENGTHS ARRAY FOR EVEN numPoints
    
    # Build sidesLen array for ODD numPoints
    if numPoints % 2 != 0:
        numPointsOver2 = int (numPoints / 2)
       
        # Fill from 0 to numPoints/2 INCLUDED
        for i in range(1, numPointsOver2 + 1):
            sidesLen.append(round(sqrt((points[i][0] - points[0][0]) * (points[i][0] - points[0][0]) + (points[i][1] - points[0][1]) * (points[i][1] - points[0][1]))))

        # Fill numPoints/2 + 1 to numPoints - 1
        for i in range(numPointsOver2 + 1, numPoints):
            sidesLen.append(sidesLen[numPoints - i])
    # END OF BUILD SIDES LENGTHS ARRAY FOR ODD numPoints
    if showDebug == True:
        for i in range(len(sidesLen)):
            print("sidesLen[", str(i), "]:", sidesLen[i])
    
##### END OF POPULATEPOINTSANDLINELENGTHS FUNCTION



##### START OF createRefLine FUNCTION
def createRefLine():
    bpy.ops.mesh.primitive_plane_add(enter_editmode=True, align='WORLD', location=(0, 0, 0), scale=(100, 100, 10))
    bpy.ops.mesh.select_all(action='SELECT')
    bpy.ops.transform.resize(value=(50, 0.9, 1))
    bpy.ops.transform.translate(value=(50, 0, 0))
    bpy.ops.object.editmode_toggle()
    bpy.context.object.name="LineRef"
##### END OF createRefLine FUNCTION



##### CREATE SHADERS FUNCTION
def createShaders():
    # EMISSION SHADER: CREATE AN EMISSION SHADER SO THAT WE CAN SEE THE LINE
    # EMISSION SHADER: NEW SHADER
    COLOR = 0
    STRENGTH = 1
    COLOR_NAME = 2
    if showColMats == True:
        print("------->I have the following colors:")
        for i in range(len(colors_and_strengths)):
            print("------------>", colors_and_strengths[i])
    
    global emission_mat
    nodes = []
    material_output = []
    node_emission = []
    links = []

    # create as many materials as we have colors
    for col_or in range(len(colors_and_strengths)):
        emission_mat.append(bpy.data.materials.new(name="Emission_" + colors_and_strengths[col_or][COLOR_NAME]))
        emission_mat[col_or].use_nodes = True
        nodes.append(emission_mat[col_or].node_tree.nodes)
        material_output.append(nodes[col_or].get('Material Output'))
        node_emission.append(nodes[col_or].new(type='ShaderNodeEmission'))
        node_emission[col_or].inputs[0].default_value = colors_and_strengths[col_or][COLOR] # RGB + Alpha
        node_emission[col_or].inputs[1].default_value = colors_and_strengths[col_or][STRENGTH] # strength
        links.append(emission_mat[col_or].node_tree.links)
        new_link = links[col_or].new(node_emission[col_or].outputs[0], material_output[col_or].inputs[0])
        
    if showColMats == True:
        for i in range(len(emission_mat)):
            print("Material:", emission_mat[i])
##### EN OF CREATE SHADERS FUNCTION



##### START OF DUPANDMOVEANDROTATELINE FUNCTION
def dupAndMoveAndRotateLine(objectGiven, contextGiven, xGiven, yGiven, angleGiven, size):
    #bpy.ops.object.delete(use_global=True, confirm=False)
    global lineNr
    objectGiven.duplicate_move()
    bpy.context.object.name="Line_0_" + str(lineNr)
    lineNr += 1
    objectGiven.rotation_clear()
    contextGiven.rotation_euler[2] = angleGiven
    objectGiven.scale_clear()
    bpy.ops.transform.resize(value=size)
    contextGiven.location[0] = xGiven
    contextGiven.location[1] = yGiven
##### END OF DUPANDMOVEANDROTATELINE FUNCTION




# LET'S HAVE FUN NOW!    
purgeOldMaterials() # print("\n\n------->Calling purgeOldMaterials...")
removeOldLines() # print("------->Calling removeOldLines...")
populatePointsAndLineLengths() # print("------->Calling populatePointsAndLineLengths...")
createRefLine() # print("------->Calling createRefLine...")
createShaders() # print("------->Calling createShaders...")
bpy.data.objects['LineRef'].data.materials.append(emission_mat[0]) # ASSIGN EMISSION SHADER TO THE REFERENCE LINE..

# NOW WE HAVE A REFERENCE LINE WITH AN EMISSION SHADER, LET'S MOVE IT OUT OF THE WAY
bpy.ops.transform.translate(value=(-sidesLen[1] / 2, 0, 0)) # Move the reference line out of the way
bpy.ops.transform.resize(value=(2, 1, 1)) # Resize the reference line

# draw numPoints lines on periphery
for i in range(numPoints):
    dupAndMoveAndRotateLine(bpy.ops.object, bpy.context.object, points[i][0], points[i][1], (i) * tau * (1 / numPoints) + (tau / 2) * (1 / 2 + 1/numPoints), (sidesLen[1] / 100, 1, 1))

# Apply materials to lines
for i in range(numPoints):
    bpy.data.objects['Line_0_' + str(i)].data.materials.clear()
    bpy.data.objects['Line_0_' + str(i)].data.materials.append(emission_mat[i % len(emission_mat) - 0])
Summary

This text will be hidden

I don’t quite understand what is the problem, do you mind to explain and illustrate it a little bit?

Run the code and you will see that the last line ends up at the center instead of on the periphery and the LineRef is in the periphery (and is longer, which I don’t mind.

And, if you open the materials, you’ll see a BSDF that is not used…

I solved the issue with removing the BSDFs from the materials, and still waiting for ideas about the last line and the ref line…