本日は Blender の技術調査枠です。
Blender2.8で利用可能なpythonスクリプトを作ります。
ノードグループの作成
ノードグループを利用して入力項目をシンプルにしたマテリアルを指定オブジェクトに追加します。
ノードグループの作成のほか、ノードの配置や入力項目の表示形式について調整を行っています。
・Script_add_materialslot_nodegroupmaterial.py
# bpyインポート import bpy # 指定オブジェクトにノードグループの新規マテリアルを参照するマテリアルスロットを作成する # (オブジェクト名指定) def add_materialslot_nodegroupmaterial_checker(arg_objectname="Default", arg_materialname="DefaultMaterial") -> bool: """指定オブジェクトにノードグループの新規マテリアルを参照するマテリアルスロットを作成する Args: arg_objectname (str, optional): 指定オブジェクト名. Defaults to "Default". arg_materialname (str, optional): 作成マテリアル名. Defaults to "DefaultMaterial". Returns: bool: 実行正否 """ # 指定オブジェクトを取得する # (get関数は対象が存在しない場合 None が返る) selectob = bpy.data.objects.get(arg_objectname) # 指定オブジェクトが存在するか確認する if selectob == None: # 指定オブジェクトが存在しない場合は処理しない return False # 指定オブジェクトがメッシュオブジェクトか確認する if selectob.type != 'MESH': # メッシュオブジェクトでない場合は処理しない return False # 指定オブジェクトにノードグループの新規マテリアルを参照するマテリアルスロットを作成する add_materialslot_nodegroupmaterial(arg_object=selectob, arg_materialname=arg_materialname) return True # 指定オブジェクトにノードグループの新規マテリアルを参照するマテリアルスロットを作成する def add_materialslot_nodegroupmaterial(arg_object:bpy.types.Object, arg_materialname="DefaultMaterial") -> bool: """指定オブジェクトにノードグループの新規マテリアルを参照するマテリアルスロットを作成する Args: arg_object (bpy.types.Object): 指定オブジェクト arg_materialname (str, optional): 作成マテリアル名. Defaults to "DefaultMaterial". Returns: bool: 実行正否 """ # 空のノードの新規マテリアルを作成する make_mat = new_material_emptynode(arg_materialname=arg_materialname) # 作成したマテリアルをオブジェクトのマテリアルスロットに追加する make_matslot = add_materialslot_target(arg_object=arg_object, arg_material=make_mat) # マテリアルのノードツリーに出力ノードを追加する make_outputnode = add_outputnode_simple(arg_material=make_mat) # ノードグループを作成する make_nodegroup = new_nodegroup_simplebsdf() # マテリアルのノードツリーにシンプルなBSDF設定のノードグループを追加する make_shadenode = add_nodegroup_simplebsdf(arg_material=make_mat, arg_nodegroup=make_nodegroup) # シンプルなBSDF設定のノードグループの入力UIを調整する make_shadenode = setting_nodegroup_simplebsdf_ui(arg_node=make_shadenode) # 指定マテリアルのノード入出力をリンクする link_node_target(arg_material=make_mat, arg_output=make_shadenode.outputs[0], arg_input=make_outputnode.inputs[0]) return True # 空ノードの新規マテリアルを作成する def new_material_emptynode(arg_materialname:str="EmptyNodeMaterial") -> bpy.types.Material: """空ノードの新規マテリアルを作成する Args: arg_materialname (str, optional): 作成マテリアル名. Defaults to "EmptyNodeMaterial". Returns: bpy.types.Material: 作成マテリアルの参照 """ # 新規マテリアルを作成する newmaterial = bpy.data.materials.new(arg_materialname) # ノードを使用する newmaterial.use_nodes = True # 新規マテリアルのノード参照を取得する mat_nodes = newmaterial.node_tree.nodes # マテリアル内の全ノードを走査する for delete_node in mat_nodes: # ノードを削除する mat_nodes.remove(delete_node) return newmaterial # 指定オブジェクトのマテリアルスロットに指定マテリアルを追加する def add_materialslot_target(arg_object:bpy.types.Object, arg_material:bpy.types.Material) -> bpy.types.MaterialSlot: """指定オブジェクトのマテリアルスロットに指定マテリアルを追加する Args: arg_object (bpy.types.Object): 指定オブジェクト arg_material (bpy.types.Material): 指定マテリアル Returns: bpy.types.MaterialSlot: 作成マテリアルスロットの参照 """ # 指定オブジェクトがメッシュオブジェクトか確認する if arg_object.type != 'MESH': # メッシュオブジェクトでない場合は処理しない return False # メッシュデータの参照を取得する mesh = arg_object.data # メッシュのマテリアルを追加する mesh.materials.append(arg_material) # 追加したマテリアルスロットを取得する add_matslot = arg_object.material_slots[-1] return add_matslot # 指定マテリアルのノード入出力をリンクする def link_node_target(arg_material:bpy.types.Material, arg_output:bpy.types.NodeSocket, arg_input:bpy.types.NodeSocket) -> bpy.types.NodeLink: """指定マテリアルのノード入出力をリンクする Args: arg_material (bpy.types.Material): 指定マテリアル arg_output (bpy.types.NodeSocket): 接続出力ソケット arg_input (bpy.types.NodeSocket): 接続入力ソケット Returns: bpy.types.NodeLink: ノードリンクの参照 """ # ターゲットマテリアルのノードリンク参照を取得する mat_links = arg_material.node_tree.links # 指定ノードの入出力を接続する mat_link = mat_links.new(arg_output, arg_input) return mat_link # マテリアルのノードツリーに出力ノードを追加する def add_outputnode_simple(arg_material:bpy.types.Material) -> bpy.types.Node: """マテリアルのノードツリーに出力ノードを追加する Args: arg_material (bpy.types.Material): 指定マテリアル Returns: bpy.types.Node: 作成ノードの参照 """ # 新規マテリアルのノード参照を取得する mat_nodes = arg_material.node_tree.nodes # 出力ノードを追加する output_node = mat_nodes.new(type='ShaderNodeOutputMaterial') output_node.location = (100, 0) return output_node # マテリアルのノードツリーにノードグループを追加する def add_nodegroup_simplebsdf(arg_material:bpy.types.Material, arg_nodegroup:bpy.types.NodeGroup) -> bpy.types.Node: """マテリアルのノードツリーにノードグループを追加する Args: arg_material (bpy.types.Material): 指定マテリアル arg_nodegroup (bpy.types.NodeGroup): 指定ノードグループ Returns: bpy.types.Node: 作成ノードの参照 """ # 新規マテリアルのノードグループ参照を取得する mat_nodes = arg_material.node_tree.nodes # ノードグループを追加する nodegroup_node = mat_nodes.new(type='ShaderNodeGroup') nodegroup_node.location = (-100, 0) # データの参照をカスタムノードに変更する nodegroup_node.node_tree = bpy.data.node_groups[arg_nodegroup.name] return nodegroup_node # シンプルなBSDF設定を構成するノードグループを作成する def new_nodegroup_simplebsdf() -> bpy.types.NodeGroup: """シンプルなBSDF設定を構成するノードグループを作成する Returns: bpy.types.NodeGroup: 作成ノードグループの参照 """ # ノードグループ名を定義する nodegroup_name = "SimpleBSDFNodeGroup" # データ内に既に同名のノードグループが定義されているか確認する # (get関数は対象が存在しない場合 None が返る) get_nodegroup = bpy.data.node_groups.get(nodegroup_name) # ノードグループが取得できたか確認する if get_nodegroup != None: # 既に同名のノードグループが定義されている場合はこれを返す return get_nodegroup # ノードグループデータを新規作成する new_nodegroup = bpy.data.node_groups.new(name=nodegroup_name, type='ShaderNodeTree') # ノードグループに入力ノードを作成する group_inputnode = add_nodegroup_simplebsdf_inputs(arg_nodegroup=new_nodegroup) # ノードグループに出力ノードを作成する group_outputnode = add_nodegroup_simplebsdf_outputs(arg_nodegroup=new_nodegroup) # ノードグループにBSDFノードを作成する group_bsdfnode = add_nodegroup_simplebsdf_bsdfnode(arg_nodegroup=new_nodegroup) # ノードグループにRGBミックスノードを作成する group_rgbmix = add_nodegroup_simplebsdf_rgbmixnode(arg_nodegroup=new_nodegroup) # ノードグループを構成するのリンク情報を設定する group_links = add_nodegroup_simplebsdf_links( arg_nodegroup=new_nodegroup, arg_inputnode=group_inputnode, arg_outputnode=group_outputnode, arg_bsdfnode=group_bsdfnode, arg_rgbmix=group_rgbmix ) return new_nodegroup # シンプルなBSDF設定を構成するノードグループの入力ノードを作成する def add_nodegroup_simplebsdf_inputs(arg_nodegroup:bpy.types.NodeGroup) -> bpy.types.Node: """シンプルなBSDF設定を構成するノードグループの入力ノードを作成する Args: arg_nodegroup (bpy.types.NodeGroup): 指定ノードグループ Returns: bpy.types.Node: 作成ノードの参照 """ # ノードグループの入力情報を作成する group_inputs = arg_nodegroup.nodes.new(type='NodeGroupInput') # 入力ノードの配置座標を設定する group_inputs.location = (-550,0) # ベースカラーの入力ソケットを設定する socket_basecolor = arg_nodegroup.inputs.new('NodeSocketColor','Base Color') socket_basecolor.default_value = (0.8, 0.8, 0.8, 1.0) # メタリックの入力ソケットを設定する socket_metallic = arg_nodegroup.inputs.new('NodeSocketFloatFactor','Metallic') socket_metallic.default_value = 0.0 socket_metallic.min_value = 0.0 socket_metallic.max_value = 1.0 # 粗さの入力ソケットを設定する socket_roughness = arg_nodegroup.inputs.new('NodeSocketFloatFactor','Roughness') socket_roughness.default_value = 0.5 socket_roughness.min_value = 0.0 socket_roughness.max_value = 1.0 # 透過切り替えの入力ソケットを設定する socket_transmission = arg_nodegroup.inputs.new('NodeSocketInt','Transmission') socket_transmission.default_value = 0 socket_transmission.min_value = 0 socket_transmission.max_value = 1 # エミッション強度の入力ソケットを設定する socket_emission = arg_nodegroup.inputs.new('NodeSocketFloatFactor','Emission') socket_emission.default_value = 0.0 socket_emission.min_value = 0.0 socket_emission.max_value = 1.0 # 法線情報の入力ソケットを設定する socket_normal = arg_nodegroup.inputs.new('NodeSocketVector','Normal') return group_inputs # シンプルなBSDF設定を構成するノードグループの出力ノードを作成する def add_nodegroup_simplebsdf_outputs(arg_nodegroup:bpy.types.NodeGroup) -> bpy.types.Node: """シンプルなBSDF設定を構成するノードグループの出力ノードを作成する Args: arg_nodegroup (bpy.types.NodeGroup): 指定ノードグループ Returns: bpy.types.Node: 作成ノードの参照 """ # ノードグループの入力情報を作成する group_outputs = arg_nodegroup.nodes.new(type='NodeGroupOutput') # 入力ノードの配置座標を設定する group_outputs.location = (500,0) # シェーダーの出力ソケットを設定する socket_bsdf = arg_nodegroup.outputs.new('NodeSocketShader','BSDF') return group_outputs # シンプルなBSDF設定を構成するノードグループのBSDFノードを作成する def add_nodegroup_simplebsdf_bsdfnode(arg_nodegroup:bpy.types.NodeGroup) -> bpy.types.Node: """シンプルなBSDF設定を構成するノードグループのBSDFノードを作成する Args: arg_nodegroup (bpy.types.NodeGroup): 指定ノードグループ Returns: bpy.types.Node: 作成ノードの参照 """ # ノードグループにプリンシプルBSDFノードを作成する group_bsdf = arg_nodegroup.nodes.new(type='ShaderNodeBsdfPrincipled') # BSDFノードの配置座標を設定する group_bsdf.location = (100,0) return group_bsdf # シンプルなBSDF設定を構成するノードグループのRGBミックスノードを作成する def add_nodegroup_simplebsdf_rgbmixnode(arg_nodegroup:bpy.types.NodeGroup) -> bpy.types.Node: """シンプルなBSDF設定を構成するノードグループのRGBミックスノードを作成する Args: arg_nodegroup (bpy.types.NodeGroup): 指定ノードグループ Returns: bpy.types.Node: 作成ノードの参照 """ # ノードグループにRGBミックスノードを作成する group_rgbmix = arg_nodegroup.nodes.new(type='ShaderNodeMixRGB') # RGBミックスの配置座標を設定する group_rgbmix.location = (-300,-400) # カラー1のソケットを設定する(黒色) input_color1 = group_rgbmix.inputs['Color1'] input_color1.default_value = (0.0, 0.0, 0.0, 1.0) return group_rgbmix # シンプルなBSDF設定を構成するノードグループの入力UIを調整する def setting_nodegroup_simplebsdf_ui(arg_node:bpy.types.Node) -> bpy.types.Node: """シンプルなBSDF設定を構成するノードグループの入力UIを調整する Args: arg_node (bpy.types.Node): 指定ノードグループ(ノード参照) Returns: bpy.types.Node: 作成ノードの参照 """ # ノーマル設定のデフォルト値を隠蔽する input_normal = arg_node.inputs['Normal'] input_normal.hide_value = True return arg_node # シンプルなBSDF設定を構成するノードグループのノードリンクを作成する def add_nodegroup_simplebsdf_links(arg_nodegroup:bpy.types.NodeGroup, arg_inputnode:bpy.types.Node, arg_outputnode:bpy.types.Node, arg_bsdfnode:bpy.types.Node, arg_rgbmix:bpy.types.Node) -> bpy.types.NodeLinks: """シンプルなBSDF設定を構成するノードグループのノードリンクを作成する Args: arg_nodegroup (bpy.types.NodeGroup): 指定ノードグループ arg_inputnode (bpy.types.Node): 入力ノード arg_outputnode (bpy.types.Node): 出力ノード arg_bsdfnode (bpy.types.Node): BSDFノード arg_rgbmix (bpy.types.Node): RGBミックスノード Returns: bpy.types.NodeLinks: 作成ノードリンクの参照 """ # ノードリンクを取得する nodegroup_links = arg_nodegroup.links # 入力ノードへの接続を行う # ベースカラー # (inputベースカラー -> bsdfベースカラー) nodegroup_links.new(arg_inputnode.outputs['Base Color'], arg_bsdfnode.inputs['Base Color']) # (inputベースカラー -> rgbmixカラー2) nodegroup_links.new(arg_inputnode.outputs['Base Color'], arg_rgbmix.inputs['Color2']) # メタリック # (inputメタリック -> bsdfメタリック) nodegroup_links.new(arg_inputnode.outputs['Metallic'], arg_bsdfnode.inputs['Metallic']) # 粗さ(input粗さ -> bsdf粗さ) nodegroup_links.new(arg_inputnode.outputs['Roughness'], arg_bsdfnode.inputs['Roughness']) # 透過(input透過 -> bsdf伝播) nodegroup_links.new(arg_inputnode.outputs['Transmission'], arg_bsdfnode.inputs['Transmission']) # 放射 # (input放射 -> rgbmix係数) nodegroup_links.new(arg_inputnode.outputs['Emission'], arg_rgbmix.inputs['Fac']) # ノーマル # (inputノーマル -> bsdfノーマル) nodegroup_links.new(arg_inputnode.outputs['Normal'], arg_bsdfnode.inputs['Normal']) # ノードグループ内の接続を行う # 放射 # (rgbmix出力 -> bsdf放射) nodegroup_links.new(arg_rgbmix.outputs['Color'], arg_bsdfnode.inputs['Emission']) # 出力ノードへの接続を行う # シェーダ出力 # (bsdfシェーダ出力 -> outputシェーダ出力) nodegroup_links.new(arg_bsdfnode.outputs['BSDF'], arg_outputnode.inputs['BSDF']) return nodegroup_links # 関数の実行例 add_materialslot_nodegroupmaterial_checker(arg_objectname = "Cube", arg_materialname = "TestMaterial")
アドオンバージョン
上記スクリプトをアドオン化したものです。
マテリアルのプロパティタブにパネルを追加します。
現在のアクティブオブジェクト(プロパティタブを開いているオブジェクト)にマテリアルを追加します。
・Script_add_materialslot_nodegroupmaterial.py
# bl_infoでプラグインに関する情報の定義を行う bl_info = { "name": "HoloMon Custom Material Add Addon", # プラグイン名 "author": "HoloMon", # 制作者名 "version": (1, 0), # バージョン "blender": (2, 80, 0), # 動作可能なBlenderバージョン "support": "TESTING", # サポートレベル "category": "Properties", # カテゴリ名 "location": "Properties > Material > HoloMon", # ロケーション "description": "Addon Custom Material Add", # 説明文 "location": "", # 機能の位置付け "warning": "", # 注意点やバグ情報 "doc_url": "", # ドキュメントURL } # 利用するタイプやメソッドのインポート import bpy from bpy.types import Operator, Panel, PropertyGroup from bpy.props import PointerProperty # 継承するクラスの命名規則は以下の通り # [A-Z][A-Z0-9_]*_(継承クラスごとの識別子)_[A-Za-z0-9_]+ # クラスごとの識別子は以下の通り # bpy.types.Operator OT # bpy.types.Panel PT # bpy.types.Header HT # bpy.types.MENU MT # bpy.types.UIList UL # Panelクラスの作成 # 参考URL:https://docs.blender.org/api/current/bpy.types.Panel.html class HOLOMON_PT_addon_custom_material_add(Panel): # パネルのラベル名を定義する # パネルを折りたたむパネルヘッダーに表示される bl_label = "Custom Material Add Addon Panel" # クラスのIDを定義する # 命名規則は CATEGORY_PT_name bl_idname = "HOLOMON_PT_custom_material_add" # パネルを使用する領域を定義する # 利用可能な識別子は以下の通り # EMPTY:無し # VIEW_3D:3Dビューポート # IMAGE_EDITOR:UV/画像エディター # NODE_EDITOR:ノードエディター # SEQUENCE_EDITOR:ビデオシーケンサー # CLIP_EDITOR:ムービークリップエディター # DOPESHEET_EDITOR:ドープシート # GRAPH_EDITOR:グラフエディター # NLA_EDITOR:非線形アニメーション # TEXT_EDITOR:テキストエディター # CONSOLE:Pythonコンソール # INFO:情報、操作のログ、警告、エラーメッセージ # TOPBAR:トップバー # STATUSBAR:ステータスバー # OUTLINER:アウトライナ # PROPERTIES:プロパティ # FILE_BROWSER:ファイルブラウザ # PREFERENCES:設定 bl_space_type = 'PROPERTIES' # 表示領域のコンテンツを定義する bl_context = 'material' # パネルが使用される領域を定義する # 利用可能な識別子は以下の通り # ['WINDOW'、 'HEADER'、 'CHANNELS'、 'TEMPORARY'、 'UI'、 # 'TOOLS'、 'TOOL_PROPS'、 'PREVIEW'、 'HUD'、 'NAVIGATION_BAR'、 # 'EXECUTE'、 'FOOTER'の列挙型、 'TOOL_HEADER'] bl_region_type = 'WINDOW' # パネルタイプのオプションを定義する # DEFAULT_CLOSED:作成時にパネルを開くか折りたたむ必要があるかを定義する。 # HIDE_HEADER:ヘッダーを非表示するかを定義する。Falseに設定するとパネルにはヘッダーが表示される。 # デフォルトは {'DEFAULT_CLOSED'} bl_options = {'DEFAULT_CLOSED'} # パネルの表示順番を定義する # 小さい番号のパネルは、大きい番号のパネルの前にデフォルトで順序付けられる # デフォルトは 0 bl_order = 255 # パネルのカテゴリ名称を定義する # 3Dビューポートの場合、サイドバーの名称になる # デフォルトは名称無し bl_category = "HoloMon" # 描画の定義 def draw(self, context): # Operatorをボタンとして配置する draw_layout = self.layout # 要素行を作成する button_row = draw_layout.row() # オブジェクト指定のサイズ縮小を実行するボタンを配置する button_row.operator("holomon.custom_material_add") # Operatorクラスの作成 # 参考URL:https://docs.blender.org/api/current/bpy.types.Operator.html class HOLOMON_OT_addon_custom_material_add(Operator): # クラスのIDを定義する # (Blender内部で参照する際のIDに利用) bl_idname = "holomon.custom_material_add" # クラスのラベルを定義する # (デフォルトのテキスト表示などに利用) bl_label = "CUSTOM MATERIAL ADD" # クラスの説明文 # (マウスオーバー時に表示) dl_description = "Custom Material Add Addon Description" # クラスの属性 # 以下の属性を設定できる # REGISTER : Operatorを情報ウィンドウに表示し、やり直しツールバーパネルをサポートする # UNDO : 元に戻すイベントをプッシュする(Operatorのやり直しに必要) # UNDO_GROUPED : Operatorの繰り返しインスタンスに対して単一の取り消しイベントをプッシュする # BLOCKING : 他の操作がマウスポインタ―を使用できないようにブロックする # MACRO : Operatorがマクロであるかどうかを確認するために使用する # GRAB_CURSOR : 継続的な操作が有効な場合にオペレーターがマウスポインターの動きを参照して、操作を有効にする # GRAB_CURSOR_X : マウスポインターのX軸の動きのみを参照する # GRAB_CURSOR_Y : マウスポインターのY軸の動きのみを参照する # PRESET : Operator設定を含むプリセットボタンを表示する # INTERNAL : 検索結果からOperatorを削除する # 参考URL:https://docs.blender.org/api/current/bpy.types.Operator.html#bpy.types.Operator.bl_options bl_options = {'REGISTER', 'UNDO'} # Operator実行時の処理 def execute(self, context): # シーンのアクティブなオブジェクトを取得する # (プロパティのマテリアルタブを開いているオブジェクトに処理を行う) target_obj = context.view_layer.objects.active # 指定中のオブジェクトを確認する if target_obj == None: # オブジェクトが指定されていない場合はエラーメッセージを表示する self.report({'ERROR'}, "No objects selected.") return {'CANCELLED'} # 指定オブジェクトがメッシュオブジェクトか確認する if target_obj.type != 'MESH': # メッシュオブジェクトでない場合は処理しない self.report({'ERROR'}, "No Mesh selected.") return {'CANCELLED'} # 指定のカーブオブジェクトの長さを取得する length = add_materialslot_nodegroupmaterial(arg_object=target_obj, arg_materialname="CustomMaterial") return {'FINISHED'} # PropertyGroupクラスの作成 # 参考URL:https://docs.blender.org/api/current/bpy.types.PropertyGroup.html class HOLOMON_addon_custom_material_add_properties(PropertyGroup): # オブジェクト選択時のチェック関数を定義する def prop_object_select_poll(self, context, ): # メッシュオブジェクトのみ選択可能 if(context and context.type in ('MESH', )): return True return False # シーン上のパネルに表示するオブジェクト選択用のカスタムプロパティを定義する prop_objectslect: PointerProperty( name = "Select Object", # プロパティ名 type = bpy.types.Object, # タイプ description = "", # 説明文 poll = prop_object_select_poll, # チェック関数 ) # ※ アクティブオブジェクトを指定する仕様としたため # オブジェクト選択のカスタムプロパティは利用しない # 登録に関する処理 # 登録対象のクラス名 regist_classes = ( HOLOMON_PT_addon_custom_material_add, HOLOMON_OT_addon_custom_material_add, HOLOMON_addon_custom_material_add_properties, ) # 作成クラスと定義の登録メソッド def register(): # カスタムクラスを登録する for regist_cls in regist_classes: bpy.utils.register_class(regist_cls) # シーン情報にカスタムプロパティを登録する bpy.types.Scene.holomon_custom_material_add = PointerProperty(type=HOLOMON_addon_custom_material_add_properties) # 作成クラスと定義の登録解除メソッド def unregister(): # シーン情報のカスタムプロパティを削除する del bpy.types.Scene.holomon_custom_material_add # カスタムクラスを解除する for regist_cls in regist_classes: bpy.utils.unregister_class(regist_cls) # 指定オブジェクトにノードグループの新規マテリアルを参照するマテリアルスロットを作成する def add_materialslot_nodegroupmaterial(arg_object:bpy.types.Object, arg_materialname="DefaultMaterial") -> bool: """指定オブジェクトにノードグループの新規マテリアルを参照するマテリアルスロットを作成する Args: arg_object (bpy.types.Object): 指定オブジェクト arg_materialname (str, optional): 作成マテリアル名. Defaults to "DefaultMaterial". Returns: bool: 実行正否 """ # 空のノードの新規マテリアルを作成する make_mat = new_material_emptynode(arg_materialname=arg_materialname) # 作成したマテリアルをオブジェクトのマテリアルスロットに追加する make_matslot = add_materialslot_target(arg_object=arg_object, arg_material=make_mat) # マテリアルのノードツリーに出力ノードを追加する make_outputnode = add_outputnode_simple(arg_material=make_mat) # ノードグループを作成する make_nodegroup = new_nodegroup_simplebsdf() # マテリアルのノードツリーにシンプルなBSDF設定のノードグループを追加する make_shadenode = add_nodegroup_simplebsdf(arg_material=make_mat, arg_nodegroup=make_nodegroup) # シンプルなBSDF設定のノードグループの入力UIを調整する make_shadenode = setting_nodegroup_simplebsdf_ui(arg_node=make_shadenode) # 指定マテリアルのノード入出力をリンクする link_node_target(arg_material=make_mat, arg_output=make_shadenode.outputs[0], arg_input=make_outputnode.inputs[0]) return True # 空ノードの新規マテリアルを作成する def new_material_emptynode(arg_materialname:str="EmptyNodeMaterial") -> bpy.types.Material: """空ノードの新規マテリアルを作成する Args: arg_materialname (str, optional): 作成マテリアル名. Defaults to "EmptyNodeMaterial". Returns: bpy.types.Material: 作成マテリアルの参照 """ # 新規マテリアルを作成する newmaterial = bpy.data.materials.new(arg_materialname) # ノードを使用する newmaterial.use_nodes = True # 新規マテリアルのノード参照を取得する mat_nodes = newmaterial.node_tree.nodes # マテリアル内の全ノードを走査する for delete_node in mat_nodes: # ノードを削除する mat_nodes.remove(delete_node) return newmaterial # 指定オブジェクトのマテリアルスロットに指定マテリアルを追加する def add_materialslot_target(arg_object:bpy.types.Object, arg_material:bpy.types.Material) -> bpy.types.MaterialSlot: """指定オブジェクトのマテリアルスロットに指定マテリアルを追加する Args: arg_object (bpy.types.Object): 指定オブジェクト arg_material (bpy.types.Material): 指定マテリアル Returns: bpy.types.MaterialSlot: 作成マテリアルスロットの参照 """ # 指定オブジェクトがメッシュオブジェクトか確認する if arg_object.type != 'MESH': # メッシュオブジェクトでない場合は処理しない return False # メッシュデータの参照を取得する mesh = arg_object.data # メッシュのマテリアルを追加する mesh.materials.append(arg_material) # 追加したマテリアルスロットを取得する add_matslot = arg_object.material_slots[-1] return add_matslot # 指定マテリアルのノード入出力をリンクする def link_node_target(arg_material:bpy.types.Material, arg_output:bpy.types.NodeSocket, arg_input:bpy.types.NodeSocket) -> bpy.types.NodeLink: """指定マテリアルのノード入出力をリンクする Args: arg_material (bpy.types.Material): 指定マテリアル arg_output (bpy.types.NodeSocket): 接続出力ソケット arg_input (bpy.types.NodeSocket): 接続入力ソケット Returns: bpy.types.NodeLink: ノードリンクの参照 """ # ターゲットマテリアルのノードリンク参照を取得する mat_links = arg_material.node_tree.links # 指定ノードの入出力を接続する mat_link = mat_links.new(arg_output, arg_input) return mat_link # マテリアルのノードツリーに出力ノードを追加する def add_outputnode_simple(arg_material:bpy.types.Material) -> bpy.types.Node: """マテリアルのノードツリーに出力ノードを追加する Args: arg_material (bpy.types.Material): 指定マテリアル Returns: bpy.types.Node: 作成ノードの参照 """ # 新規マテリアルのノード参照を取得する mat_nodes = arg_material.node_tree.nodes # 出力ノードを追加する output_node = mat_nodes.new(type='ShaderNodeOutputMaterial') output_node.location = (100, 0) return output_node # マテリアルのノードツリーにノードグループを追加する def add_nodegroup_simplebsdf(arg_material:bpy.types.Material, arg_nodegroup:bpy.types.NodeGroup) -> bpy.types.Node: """マテリアルのノードツリーにノードグループを追加する Args: arg_material (bpy.types.Material): 指定マテリアル arg_nodegroup (bpy.types.NodeGroup): 指定ノードグループ Returns: bpy.types.Node: 作成ノードの参照 """ # 新規マテリアルのノードグループ参照を取得する mat_nodes = arg_material.node_tree.nodes # ノードグループを追加する nodegroup_node = mat_nodes.new(type='ShaderNodeGroup') nodegroup_node.location = (-100, 0) # データの参照をカスタムノードに変更する nodegroup_node.node_tree = bpy.data.node_groups[arg_nodegroup.name] return nodegroup_node # シンプルなBSDF設定を構成するノードグループを作成する def new_nodegroup_simplebsdf() -> bpy.types.NodeGroup: """シンプルなBSDF設定を構成するノードグループを作成する Returns: bpy.types.NodeGroup: 作成ノードグループの参照 """ # ノードグループ名を定義する nodegroup_name = "SimpleBSDFNodeGroup" # データ内に既に同名のノードグループが定義されているか確認する # (get関数は対象が存在しない場合 None が返る) get_nodegroup = bpy.data.node_groups.get(nodegroup_name) # ノードグループが取得できたか確認する if get_nodegroup != None: # 既に同名のノードグループが定義されている場合はこれを返す return get_nodegroup # ノードグループデータを新規作成する new_nodegroup = bpy.data.node_groups.new(name=nodegroup_name, type='ShaderNodeTree') # ノードグループに入力ノードを作成する group_inputnode = add_nodegroup_simplebsdf_inputs(arg_nodegroup=new_nodegroup) # ノードグループに出力ノードを作成する group_outputnode = add_nodegroup_simplebsdf_outputs(arg_nodegroup=new_nodegroup) # ノードグループにBSDFノードを作成する group_bsdfnode = add_nodegroup_simplebsdf_bsdfnode(arg_nodegroup=new_nodegroup) # ノードグループにRGBミックスノードを作成する group_rgbmix = add_nodegroup_simplebsdf_rgbmixnode(arg_nodegroup=new_nodegroup) # ノードグループを構成するのリンク情報を設定する group_links = add_nodegroup_simplebsdf_links( arg_nodegroup=new_nodegroup, arg_inputnode=group_inputnode, arg_outputnode=group_outputnode, arg_bsdfnode=group_bsdfnode, arg_rgbmix=group_rgbmix ) return new_nodegroup # シンプルなBSDF設定を構成するノードグループの入力ノードを作成する def add_nodegroup_simplebsdf_inputs(arg_nodegroup:bpy.types.NodeGroup) -> bpy.types.Node: """シンプルなBSDF設定を構成するノードグループの入力ノードを作成する Args: arg_nodegroup (bpy.types.NodeGroup): 指定ノードグループ Returns: bpy.types.Node: 作成ノードの参照 """ # ノードグループの入力情報を作成する group_inputs = arg_nodegroup.nodes.new(type='NodeGroupInput') # 入力ノードの配置座標を設定する group_inputs.location = (-550,0) # ベースカラーの入力ソケットを設定する socket_basecolor = arg_nodegroup.inputs.new('NodeSocketColor','Base Color') socket_basecolor.default_value = (0.8, 0.8, 0.8, 1.0) # メタリックの入力ソケットを設定する socket_metallic = arg_nodegroup.inputs.new('NodeSocketFloatFactor','Metallic') socket_metallic.default_value = 0.0 socket_metallic.min_value = 0.0 socket_metallic.max_value = 1.0 # 粗さの入力ソケットを設定する socket_roughness = arg_nodegroup.inputs.new('NodeSocketFloatFactor','Roughness') socket_roughness.default_value = 0.5 socket_roughness.min_value = 0.0 socket_roughness.max_value = 1.0 # 透過切り替えの入力ソケットを設定する socket_transmission = arg_nodegroup.inputs.new('NodeSocketInt','Transmission') socket_transmission.default_value = 0 socket_transmission.min_value = 0 socket_transmission.max_value = 1 # エミッション強度の入力ソケットを設定する socket_emission = arg_nodegroup.inputs.new('NodeSocketFloatFactor','Emission') socket_emission.default_value = 0.0 socket_emission.min_value = 0.0 socket_emission.max_value = 1.0 # 法線情報の入力ソケットを設定する socket_normal = arg_nodegroup.inputs.new('NodeSocketVector','Normal') return group_inputs # シンプルなBSDF設定を構成するノードグループの出力ノードを作成する def add_nodegroup_simplebsdf_outputs(arg_nodegroup:bpy.types.NodeGroup) -> bpy.types.Node: """シンプルなBSDF設定を構成するノードグループの出力ノードを作成する Args: arg_nodegroup (bpy.types.NodeGroup): 指定ノードグループ Returns: bpy.types.Node: 作成ノードの参照 """ # ノードグループの入力情報を作成する group_outputs = arg_nodegroup.nodes.new(type='NodeGroupOutput') # 入力ノードの配置座標を設定する group_outputs.location = (500,0) # シェーダーの出力ソケットを設定する socket_bsdf = arg_nodegroup.outputs.new('NodeSocketShader','BSDF') return group_outputs # シンプルなBSDF設定を構成するノードグループのBSDFノードを作成する def add_nodegroup_simplebsdf_bsdfnode(arg_nodegroup:bpy.types.NodeGroup) -> bpy.types.Node: """シンプルなBSDF設定を構成するノードグループのBSDFノードを作成する Args: arg_nodegroup (bpy.types.NodeGroup): 指定ノードグループ Returns: bpy.types.Node: 作成ノードの参照 """ # ノードグループにプリンシプルBSDFノードを作成する group_bsdf = arg_nodegroup.nodes.new(type='ShaderNodeBsdfPrincipled') # BSDFノードの配置座標を設定する group_bsdf.location = (100,0) return group_bsdf # シンプルなBSDF設定を構成するノードグループのRGBミックスノードを作成する def add_nodegroup_simplebsdf_rgbmixnode(arg_nodegroup:bpy.types.NodeGroup) -> bpy.types.Node: """シンプルなBSDF設定を構成するノードグループのRGBミックスノードを作成する Args: arg_nodegroup (bpy.types.NodeGroup): 指定ノードグループ Returns: bpy.types.Node: 作成ノードの参照 """ # ノードグループにRGBミックスノードを作成する group_rgbmix = arg_nodegroup.nodes.new(type='ShaderNodeMixRGB') # RGBミックスの配置座標を設定する group_rgbmix.location = (-300,-400) # カラー1のソケットを設定する(黒色) input_color1 = group_rgbmix.inputs['Color1'] input_color1.default_value = (0.0, 0.0, 0.0, 1.0) return group_rgbmix # シンプルなBSDF設定を構成するノードグループの入力UIを調整する def setting_nodegroup_simplebsdf_ui(arg_node:bpy.types.Node) -> bpy.types.Node: """シンプルなBSDF設定を構成するノードグループの入力UIを調整する Args: arg_node (bpy.types.Node): 指定ノードグループ(ノード参照) Returns: bpy.types.Node: 作成ノードの参照 """ # ノーマル設定のデフォルト値を隠蔽する input_normal = arg_node.inputs['Normal'] input_normal.hide_value = True return arg_node # シンプルなBSDF設定を構成するノードグループのノードリンクを作成する def add_nodegroup_simplebsdf_links(arg_nodegroup:bpy.types.NodeGroup, arg_inputnode:bpy.types.Node, arg_outputnode:bpy.types.Node, arg_bsdfnode:bpy.types.Node, arg_rgbmix:bpy.types.Node) -> bpy.types.NodeLinks: """シンプルなBSDF設定を構成するノードグループのノードリンクを作成する Args: arg_nodegroup (bpy.types.NodeGroup): 指定ノードグループ arg_inputnode (bpy.types.Node): 入力ノード arg_outputnode (bpy.types.Node): 出力ノード arg_bsdfnode (bpy.types.Node): BSDFノード arg_rgbmix (bpy.types.Node): RGBミックスノード Returns: bpy.types.NodeLinks: 作成ノードリンクの参照 """ # ノードリンクを取得する nodegroup_links = arg_nodegroup.links # 入力ノードへの接続を行う # ベースカラー # (inputベースカラー -> bsdfベースカラー) nodegroup_links.new(arg_inputnode.outputs['Base Color'], arg_bsdfnode.inputs['Base Color']) # (inputベースカラー -> rgbmixカラー2) nodegroup_links.new(arg_inputnode.outputs['Base Color'], arg_rgbmix.inputs['Color2']) # メタリック # (inputメタリック -> bsdfメタリック) nodegroup_links.new(arg_inputnode.outputs['Metallic'], arg_bsdfnode.inputs['Metallic']) # 粗さ(input粗さ -> bsdf粗さ) nodegroup_links.new(arg_inputnode.outputs['Roughness'], arg_bsdfnode.inputs['Roughness']) # 透過(input透過 -> bsdf伝播) nodegroup_links.new(arg_inputnode.outputs['Transmission'], arg_bsdfnode.inputs['Transmission']) # 放射 # (input放射 -> rgbmix係数) nodegroup_links.new(arg_inputnode.outputs['Emission'], arg_rgbmix.inputs['Fac']) # ノーマル # (inputノーマル -> bsdfノーマル) nodegroup_links.new(arg_inputnode.outputs['Normal'], arg_bsdfnode.inputs['Normal']) # ノードグループ内の接続を行う # 放射 # (rgbmix出力 -> bsdf放射) nodegroup_links.new(arg_rgbmix.outputs['Color'], arg_bsdfnode.inputs['Emission']) # 出力ノードへの接続を行う # シェーダ出力 # (bsdfシェーダ出力 -> outputシェーダ出力) nodegroup_links.new(arg_bsdfnode.outputs['BSDF'], arg_outputnode.inputs['BSDF']) return nodegroup_links # 実行時の処理 if __name__ == "__main__": # 作成クラスと定義を登録する register()