本日は Blender の小ネタ枠です。
Bevel Curve Tools アドオンを使ってBlenderで髪の毛オブジェクトを作る手順を記事にします。
前回記事の続きです。
bluebirdofoz.hatenablog.com
テクスチャの反映
今回は髪の毛オブジェクトにテクスチャを反映して、より髪の毛っぽい見た目にしていきます。
毛並の方向を揃えるため、個々のオブジェクト毎にテクスチャの反映を行っていきます。
UVマップを展開してマテリアルを設定する
既にメッシュを上下で分離しているのでそのままUV展開を行います。
[編集モード]に切り替えて、全ての面を選択した状態で[UV]->[展開]を実行し、UVマップを展開します。
次にマテリアルを設定します。
[マテリアル]タブを開き、[新規]ボタンでマテリアルを作成します。
マテリアルが生成されたらテクスチャを設定します。
[ベースカラー]のプルダウンを開き、[画像テクスチャ]を選択します。
[開く]ボタンでファイル選択ダイアログを開き、反映するテクスチャを選択します。
これでテクスチャが反映できました。
テクスチャを反映した状態の見た目は[3Dビューのシェーディング]を[マテリアルプレビュー]に変更することで確認できます。
別オブジェクトのマテリアルを設定する
別オブジェクトもテクスチャを反映していきます。
2つ目以降のオブジェクトは先ほど作成したマテリアルを選択して反映します。
処理の自動化
上記の作業を全てのメッシュに実施します。
こちらの作業もスクリプト化しました。
以下の記事の python スクリプトを元にマテリアルの作成と全オブジェクトへのマテリアル反映を行いました。
bluebirdofoz.hatenablog.com
# bpyインポート import bpy # パス操作のため import os # 指定オブジェクトに指定テクスチャを設定したプリンシプルBSDFマテリアルを作成する def new_bsdfmaterial_texture(arg_materialname="TextureMaterial", arg_texturepath="") -> bool: """指定テクスチャを設定したプリンシプルBSDFマテリアルを作成する Args: arg_materialname (str, optional): 作成マテリアル名. Defaults to "TextureMaterial". arg_texturepath (str, optional): 参照テクスチャパス. Defaults to "". Returns: bool: 実行正否 """ # テクスチャパスを確認する if arg_texturepath == "": # テクスチャパスが未設定の場合は処理しない return False # テクスチャの存在確認を行う if os.path.isfile(arg_texturepath) != True: # 指定テクスチャが存在しない場合は処理しない return False # 指定名のマテリアルを取得する check_mat = bpy.data.materials.get(arg_materialname) # 指定名のマテリアルが存在するか確認する if check_mat != None: # 指定名のマテリアルが既に存在する場合は処理しない return False # 新規マテリアルを作成する newmaterial = bpy.data.materials.new(arg_materialname) # ノードを使用する newmaterial.use_nodes = True # 処理対象のマテリアルを取得する target_mat = newmaterial # ターゲットマテリアルのノード参照を取得 mat_nodes = target_mat.node_tree.nodes # マテリアル内の全ノードを走査する for delete_node in mat_nodes: # 一旦デフォルトのノードを全て削除する mat_nodes.remove(delete_node) # テクスチャノードの追加 texture_node = mat_nodes.new(type="ShaderNodeTexImage") # テクスチャノードをアクティブにする mat_nodes.active = texture_node # 指定画像を読み込む loadimage = bpy.data.images.load(filepath=arg_texturepath) # テクスチャノードに新規画像を設定する texture_node.image = loadimage # ノードリンクの取得 mat_link = target_mat.node_tree.links # プリンシプルBSDFノードを追加する bsdf_node = mat_nodes.new(type="ShaderNodeBsdfPrincipled") # 出力ノードを追加する output_node = mat_nodes.new(type="ShaderNodeOutputMaterial") # テクスチャノードのカラーとプリンシプルBSDFノードのベースカラーを接続する mat_link.new(texture_node.outputs[0], bsdf_node.inputs[0]) # 放射ノードの放射と出力ノードのサーフェスを接続する mat_link.new(bsdf_node.outputs[0], output_node.inputs[0]) return True # 指定オブジェクトの全マテリアルを削除する def delete_material_all(arg_objectname="Default") -> bool: """指定オブジェクトに新規マテリアルを作成する Keyword Arguments: arg_objectname {str} -- 対象オブジェクト名 (default: {"Default"}) Returns: Bool -- 実行正否 """ # 指定オブジェクトを取得する # (get関数は対象が存在しない場合 None が返る) selectob = bpy.data.objects.get(arg_objectname) # 指定オブジェクトが存在するか確認する if selectob == None: # 指定オブジェクトが存在しない場合は処理しない return False # 指定オブジェクトがメッシュオブジェクトか確認する if selectob.type != 'MESH': # メッシュオブジェクトでない場合は処理しない return False # オブジェクトをアクティブにする bpy.context.view_layer.objects.active = selectob # マテリアルスロットを走査する for material_slot in selectob.material_slots: # マテリアルスロットをアクティブにする selectob.active_material = material_slot.material # マテリアルスロットを削除する bpy.ops.object.material_slot_remove() return True # 指定オブジェクトに指定名のマテリアルを追加する def add_material_target(arg_objectname="Default", arg_materialname="NewMaterial", arg_usenode=True) -> bool: """指定オブジェクトに新規マテリアルを作成する Keyword Arguments: arg_objectname {str} -- 対象オブジェクト名 (default: {"Default"}) arg_materialname {str} -- 追加マテリアル名 (default: {"NewMaterial"}) arg_usenode {bool} -- ノード利用の有無 (default: {True}) Returns: Bool -- 実行正否 """ # 指定オブジェクトを取得する # (get関数は対象が存在しない場合 None が返る) selectob = bpy.data.objects.get(arg_objectname) # 指定オブジェクトが存在するか確認する if selectob == None: # 指定オブジェクトが存在しない場合は処理しない return False # 指定オブジェクトがメッシュオブジェクトか確認する if selectob.type != 'MESH': # メッシュオブジェクトでない場合は処理しない return False # オブジェクトをアクティブにする bpy.context.view_layer.objects.active = selectob # 指定名のマテリアルを取得する add_mat = bpy.data.materials.get(arg_materialname) # 指定名のマテリアルが存在するか確認する if add_mat == None: # 指定名のマテリアルが存在しない場合は新規マテリアルを作成する add_mat = bpy.data.materials.new(arg_materialname) # ノードの利用指定を確認する if arg_usenode == True: # ノードを使用する add_mat.use_nodes = True # 指定名のマテリアルスロットを取得する check_matslot = selectob.material_slots.get(arg_materialname) # 指定マテリアルが存在するか確認する if check_matslot != None: # 指定名のマテリアルスロットが既に存在する場合は処理しない return False # マテリアルスロットを追加する bpy.ops.object.material_slot_add() # 追加したマテリアルスロットに指定名のマテリアルを設定する selectob.active_material = add_mat return True # 現在のblendファイルが存在するディレクトリパスを取得する # 未保存のプロジェクト上で実行すると、空文字が返る def get_blend_dirpath() -> str: """現在のblendが存在するディレクトリパスを取得する 未保存のプロジェクト上で実行すると、空文字が返る Returns: str: blendディレクトリパス """ # blendファイルのパスを取得 filepath = bpy.data.filepath # 空文字が返った場合は処理せず終了する if filepath == "": return "" # ディレクトリパスを取得する dirpath = os.path.dirname(filepath) return dirpath # UV展開を実行する(デフォルト設定) def project_UVmap_mesh(arg_objectname="Default") -> bool: """UV展開を実行する(デフォルト設定) Keyword Arguments: arg_objectname {str} -- 指定オブジェクト名 (default: {"Default"}) Returns: bool -- 実行正否 """ # 指定オブジェクトを取得する # (get関数は対象が存在しない場合 None が返る) selectob = bpy.data.objects.get(arg_objectname) # 指定オブジェクトが存在するか確認する if selectob == None: # 指定オブジェクトが存在しない場合は処理しない return False # オブジェクトがメッシュであるか確認する if selectob.type != 'MESH': # 指定オブジェクトがメッシュでない場合は処理しない return False # 不要なオブジェクトを選択しないように # 全てのオブジェクトを走査する for ob in bpy.context.scene.objects: # 非選択状態に設定する ob.select_set(False) # 指定のオブジェクトのみを選択状態にする selectob.select_set(True) # 対象オブジェクトをアクティブに変更する bpy.context.view_layer.objects.active = selectob # 元々の操作モードを記録する befmode = bpy.context.active_object.mode # 編集モードに移行する bpy.ops.object.mode_set(mode='EDIT', toggle=False) # 頂点を全選択した状態とする bpy.ops.mesh.select_all(action='SELECT') # デフォルト設定のUV展開を実行する bpy.ops.uv.unwrap() # オブジェクトモードに移行する bpy.ops.object.mode_set(mode='OBJECT', toggle=False) # 変更前のモードに移行する bpy.ops.object.mode_set(mode=befmode) return # マテリアル名を設定する materialname = "TextureMaterial" # テクスチャパスを作成する texturepath = get_blend_dirpath() + "\\Texture\\Fur_Texture_1024.png" # 作成マテリアルにプリンシプルBSDFノードを追加して画像ノードをカラーとして接続する new_result = new_bsdfmaterial_texture(arg_materialname=materialname, arg_texturepath=texturepath) # 全オブジェクトのUVマップを展開してマテリアルを設定する for item in bpy.data.objects: project_UVmap_mesh(arg_objectname=item.name) delete_material_all(arg_objectname=item.name) add_material_target(arg_objectname=item.name, arg_materialname=materialname)
次はUVマップの調整を行います。
bluebirdofoz.hatenablog.com