首页 > 解决方案 > Blender 2.92 Python 对象创建和材质分配

问题描述

我对 blender python 完全陌生,我确实仔细阅读了 IDE 文档,但我仍然无法解决两个问题:

我创建了一个参考对象(一个非常薄的平面,应该是一条线)。

然后我复制参考线,在代码中称为 LineRef,多次(在将其移动到 (0, 0) 之后),每个新副本都放置在一个假想圆的外围,与其他圆等距并旋转使它们形成一个内接在圆中的多边形。它们是 Line_0_0、Line_0_1 等。

然后,我给他们材料。

我遇到的两个问题是:

  1. 当我完成创建所有“线”时,我创建的最后一行和参考线似乎被交换了。我不知道我做错了什么。

  2. 当我查看每一行的材料时,我可以看到原来的 BSDF 节点仍然存在。我怎样才能摆脱它?

这是代码:

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])

标签: pythonblender

解决方案


推荐阅读