Web Top Page

BlenderのPythonスクリプトで単色のベースカラーを設定する例

シェイダーエディターの接続リンクを作っているようなコードです。
set_rgbという関数で、第1引数のオブジェクトを、第2引数のRGB不透明度指定で、色を設定します。
なお、第3引数はマテリアルの名前です。(実行でOBJECTモードになります。)
import bpy
# 引数のオブジェクトにRGBの色を設定する(OBJECTモードに変わります)
def set_rgb(obj, rgb=(0.0, 0.0, 0.0, 1.0), materialname='マテリアル.01'):
    bpy.ops.object.mode_set(mode='OBJECT')
    obj=bpy.context.active_object # 直前でアクセスしたオブジェク
    material = bpy.data.materials.new(materialname)# マテリアル生成
    material.use_nodes = True
    nodes = material.node_tree.nodes # ノードツリーを取得
    links = material.node_tree.links
    nodes.clear()  # 既存ノードをクリア
    #
    bsdf = nodes.new(type='ShaderNodeBsdfPrincipled') # ノードを作成
    bsdf.location = (0, 0)
    material_output = nodes.new(type='ShaderNodeOutputMaterial')#シェーダーの最終出力を受け取るノード取得
    material_output.location = (400, 0)
    #
    # Principled BSDF ノードの BSDF 出力を、Material Output ノードの Surface 入力に接続
    links.new(bsdf.outputs['BSDF'], material_output.inputs['Surface'])# ノード間をリンク
    #
    if not bsdf.inputs['Base Color'].is_linked:
        bsdf.inputs['Base Color'].default_value = rgb # Base Color を設定
    if len(obj.data.materials) == 0:
        obj.data.materials.append(material)  # マテリアルがない場合は追加
    else:
        obj.data.materials[0] = material  # 既存のマテリアルを置き換え
    #
    bpy.context.view_layer.update()# ビューポートを更新

bpy.ops.mesh.primitive_uv_sphere_add(radius=1, segments=8, ring_count=7, location=(-4.0, 0.0, 0.0) )
obj=bpy.context.active_object # 直前でアクセスしたオブジェク
set_rgb(obj, rgb=(0.0, 0.0, 1.0, 0.5), materialname='マテリアル青') # 青の半透明

上記は、objのオブジェクトでマテリアルを一旦クリアして一つのベースカラーを指定したマテリアルに作り直しています。
(一つのオブジェクトに複数のマテリアルを管理できますが、上記ではそれをクリアして、作り直しています。) 対して後述のset_basecolorは、既存のマテリアルのベースカラーを変更できます。



BlenderのPythonスクリプトで既存のマテリアルの単色のベースカラーを設定する。
(指定の名のマテリアルが存在しない場合、そのマテリアルを生成します。)

これを実現するset_basecolor関数を定義して利用しています。
第1引数のオブジェクトにおいて、第2引数の名前のマテリアルに第3引数のベースカラーを設定します。
以下では、UV球を生成した後にこの関数を利用て、'マテリアル.黒'と'マテリアル.白'のマテリアルを生成します。
(マティリアルプレビューにすると、先に設定した黒でレンダリングされます。)
その後に'EDIT'にして、Z軸で半径×0.8未満の面を選択状態にし、その選択面に'マテリアル.白'を割り当ていているコード例です。
# 引数のオブジェクトに、マテリアルのRGBの色を設定する(マテリアルが存在しない場合は生成する)
def set_basecolor(obj, materialname='マテリアル', rgb=(0.0, 0.0, 0.0, 1.0)):
    idx=-1
    for i in range(len(obj.data.materials)):# 既存のマテリアル検索
        print(obj.data.materials[i].name)
        if obj.data.materials[i].name.startswith(materialname):
            idx = i
            break
    #
    if idx!=-1:
        material = obj.data.materials[idx]# マテリアル取得
        for node in material.node_tree.nodes:
            if node.type=='BSDF_PRINCIPLED':bsdf=node
            if node.type=='OUTPUT_MATERIAL':material_output=node
            print(f'ノード検索:{node}')
        #
    else:
        print(f'{materialname}の名前でマテリアルの生成')
        material = bpy.data.materials.new(materialname)# マテリアル生成
        obj.data.materials.append(material)  # マテリアルがない場合は追加
        material.use_nodes = True
        material.node_tree.nodes.clear()
        bsdf = material.node_tree.nodes.new(type='ShaderNodeBsdfPrincipled') # Bsdfノードを作成
        material_output = material.node_tree.nodes.new(type='ShaderNodeOutputMaterial')#シェーダーの最終出力を受け取るノード取得
        bsdf.location = (0, 0)
        material_output.location = (400, 0)
        # Principled BSDF ノードの BSDF 出力を、Material Output ノードの Surface 入力に接続
        material.node_tree.links.new(bsdf.outputs['BSDF'], material_output.inputs['Surface'])# ノード間をリンク
    #
    bsdf.inputs['Base Color'].default_value = rgb # Base Color を設定
    bpy.context.view_layer.update()# ビューポートを更新

radius=0.01 # UV球半径
segments=16 # UV球の縦分割
ring_count=10 # UV球の角度分割

bpy.ops.mesh.primitive_uv_sphere_add(segments=segments, ring_count=ring_count, radius=radius)
bpy.ops.object.mode_set(mode='OBJECT')
eyeObj=bpy.context.active_object # 直前でアクセスしたオブジェク
set_basecolor(eyeObj, rgb=(0.0, 0.0, 0.0, 1.0), materialname='マテリアル.黒')
set_basecolor(eyeObj, rgb=(1.0, 1.0, 1.0, 1.0), materialname='マテリアル.白')

bpy.ops.object.mode_set(mode='EDIT')
import bmesh
bm = bmesh.from_edit_mesh(eyeObj.data) # 編集モード中のメッシュデータをBMeshに変換
for face in bm.faces: # 全ての面の走査
    if face.calc_center_median().z < radius*0.8: face.select=True
    else: face.select=False

bmesh.update_edit_mesh(eyeObj.data) # BMeshを更新(編集モードで、bmは引き続き編集可能)

bpy.context.object.active_material_index = 1 # 現在のマテリアルを1の指定('マテリアル.白')にする
bpy.ops.object.material_slot_assign()# 現在の選択面に選択のマテリアルを割り当て

bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.transform.rotate(value=-1.5708, orient_axis='X') # X軸で、-90度を回転




bpy.types.Object を、他のオブジェクトのローカル座標へ移動する例

set_locationという関数を定義して実現する例です。
第1引数のオブジェクトを、第2引数のオブジェクトのローカル座標に移動する関数です
(第3引数が、第2引数のオブジェクトのローカル座標です。)
この例では移動対象のICO球を、トラース(ドーナツ型?)のローカル座標で、(0,0,0) の位置に移動しています。
なお、移動対象の球をスムーズシェードにして、ローカル座標を指定するトラースのオブジェクトをフラットシェードにして、 見栄えを区別しています。
import bpy

# move_objを、objのローカル座標で移動する。
def set_location(move_obj,obj, local_location=(0,0,0) ):
    global_co = obj.matrix_world @ Vector(local_location)
    move_obj.location=global_co # 位置変更

for obj in bpy.data.objects:# 'Camera' と 'Light' 以外を全て削除する
    if obj.name=='Camera' or obj.name=='Light': continue
    bpy.data.objects.remove( obj )

bpy.ops.mesh.primitive_torus_add(location=(-2, 1, 0.5), major_segments=8, minor_segments=4)
torus_obj=bpy.context.active_object # 直前でアクセスしたオブジェク
bpy.ops.object.shade_flat() # フラットシェード指定
bpy.ops.mesh.primitive_ico_sphere_add(radius=0.3)
sphere_obj=bpy.context.active_object # 直前でアクセスしたオブジェク
bpy.ops.object.shade_smooth()# スムーズシェード指定
set_location(move_obj=sphere_obj, obj=torus_obj, local_location=(0,0,0))