Blender 4.0でPython APIを使用して外部の自作関数を使用する方法

3DCG

はじめに

この記事では、Blender 4.0でPython APIを使用して外部の自作関数を使用する方法を説明します。このプロセスは、コマンドラインからBlenderを操作し、自動化タスクを実行する際に役立ちます。


こちらの記事もおすすめ

Blender 4.0でPython APIを使用して文字を表示してレンダリングする方法
はじめにこの記事では、Blender 4.0でPython APIを使用して文字を表示し、レンダリングする手順を説明します。このプロセスは、コマンドラインからBlenderを操作し、自動化タスクを実行する際に役立ちます。こちらの記事もおすす...
Blender 4.0でPython APIを使用してフォント指定で日本語文字を表示する方法
はじめにこの記事では、Blender 4.0でPython APIを使用してフォント指定で日本語文字を表示する方法する手順を説明します。このプロセスは、コマンドラインからBlenderを操作し、自動化タスクを実行する際に役立ちます。こちらの...
Blender 4.0でPython APIを使用して平面のメッシュに画像を貼り付ける方法
はじめにこの記事では、Blender 4.0でPython APIを使用して平面のメッシュに画像を貼り付ける方法を説明します。このプロセスは、コマンドラインからBlenderを操作し、自動化タスクを実行する際に役立ちます。こちらの記事もおす...

必要なツール

  • Blender 4.0
  • 基本的なPythonの知識

クリプトの準備

background_job_module.py


import os
import sys
import pprint

sys.path.append(os.path.join(os.path.dirname(__file__), r'D:\Prj\VideoPortraitMaker\module'))
pprint.pprint(sys.path)

from scene_setup import setup_scene, configure_camera, configure_lighting
from rendering import save_and_render
from addons import enable_addon, import_image_as_plane
from helpers import set_object_scale, set_object_location
import bpy

import argparse

def parse_arguments(argv):
    parser = argparse.ArgumentParser()
    parser.add_argument("-t", "--text", dest="text", type=str, default="Blender\nPythonAPIで\n外部ファイルから\n関数を\n使用してみた",
                        help="This text will be used to render an image")
    parser.add_argument("-s", "--save", dest="save_path", metavar='FILE', default="/tmp/hello.blend",
                        help="Save the generated file to the specified path")
    parser.add_argument("-r", "--render", dest="render_path", metavar='FILE', default="/tmp/hello4",
                        help="Render an image to the specified path")
    parser.add_argument("-f", "--font", dest="font_path", type=str, default="C:\\Windows\\Fonts\\meiryob.ttc",
                        help="The path to the font file to use for rendering the text")
    parser.add_argument("-b", "--background", dest="background_path", type=str, 
                        default="D:\\Prj\\VideoPortraitMaker\\image\\background01.png",
                        help="The path to the background image file to use")

    return parser.parse_args(argv)

def setup_background(args):
    enable_addon("io_import_images_as_planes")
    import_image_as_plane(args.background_path)

    obj = bpy.data.objects.get('background01')
    set_object_scale(obj, 10.8, 21.6, 1)
    set_object_location(obj, 0, 0, -1)

def main():
    argv = sys.argv

    if "--" in argv:
        argv = argv[argv.index("--") + 1:]
    else:
        argv = []

    args = parse_arguments(argv)

    scene = bpy.context.scene
    setup_scene(scene, args.background_path, args.font_path, args.text)
    enable_addon("io_import_images_as_planes")
    import_image_as_plane(args.background_path)
    setup_background(args)

    configure_camera(scene)
    configure_lighting(scene)
    save_and_render(scene, args.save_path, args.render_path)

if __name__ == "__main__":
    main()

addons.py


import bpy              # Blender Python APIをインポート
import addon_utils      # アドオン操作用ユーティリティをインポート
import os               # OS関連の操作用モジュールをインポート

"""
[ Blender ]  ---- enable_addon() ---->  [ Addon Enabled ]
     | 
     |-- import_image_as_plane() ---->  [ Image as Plane in Scene ]
     |                                   (if image file exists)
     |
     └-- [ Error: Image file not found ]
         (if image file does not exist)

enable_addon: 指定されたアドオンがBlender内で有効化されているかを確認し、必要に応じて有効化します。
import_image_as_plane: 指定された画像ファイルが存在する場合、Blenderのシーン内に平面としてインポートします。ファイルが存在しない場合はエラーメッセージが表示されます。

"""

def enable_addon(addon_name):
    # 指定されたアドオンがロードされているかどうかをチェック
    loaded_default, loaded_state = addon_utils.check(addon_name)

    if not loaded_state:
        # アドオンがロードされていなければ、それを有効化
        addon_utils.enable(addon_name, default_set=True)
        print(f"Addon '{addon_name}' enabled.")
    else:
        # アドオンが既にロードされていれば、その旨を通知
        print(f"Addon '{addon_name}' already enabled.")

def import_image_as_plane(image_path):
    # 与えられたパスの画像ファイルが存在するかどうかをチェック
    if os.path.exists(image_path):
        # 画像ファイルが存在すれば、Blenderに平面としてインポート
        bpy.ops.import_image.to_plane(files=[{"name": image_path}])
        print(f"Image imported as plane: {image_path}")
    else:
        # 画像ファイルが存在しなければ、エラーメッセージを表示
        print(f"Image file not found: {image_path}")

helpers.py


import bpy  # Blender Python APIをインポート
import os   # OS関連の操作用モジュールをインポート

"""
[ Blender Scene ]
    |
    |--- set_object_scale() --> [ Scale Object ]
    |                             (Set x, y, z scales)
    |
    |--- set_object_location() -> [ Move Object ]
    |                             (Set x, y, z locations)
    |
    └--- create_text_object() --> [ Create Text Object ]
                                  (Create text with specified font if available)

set_object_scale: 指定されたオブジェクトのスケール(x, y, z軸の大きさ)を設定します。
set_object_location: 指定されたオブジェクトの位置(x, y, z軸上の位置)を設定します。
create_text_object: 指定されたテキストとフォントパスを使用してテキストオブジェクトを作成します。フォントファイルが存在する場合、それを使用し、存在しない場合は警告を表示します。

"""

def set_object_scale(obj, scale_x, scale_y, scale_z):
    # オブジェクトのスケールを設定
    obj.scale.x = scale_x
    obj.scale.y = scale_y
    obj.scale.z = scale_z

def set_object_location(obj, loc_x, loc_y, loc_z):
    # オブジェクトの位置を設定
    obj.location.x = loc_x
    obj.location.y = loc_y
    obj.location.z = loc_z

def create_text_object(text, font_path):
    # テキストオブジェクトを作成
    txt_data = bpy.data.curves.new(name="Text", type='FONT')  # 新しいテキストデータを作成
    txt_data.body = text                                      # テキストの内容を設定
    txt_data.align_x = 'CENTER'                               # テキストを中央揃え

    if os.path.exists(font_path):
        txt_data.font = bpy.data.fonts.load(font_path)  # 指定されたフォントをロード
    else:
        print(f"Font file not found: {font_path}")     # フォントファイルが見つからない場合の警告

    return bpy.data.objects.new(name="TextObject", object_data=txt_data)  # テキストオブジェクトを作成して返す

materials.py


import bpy  # Blender Python APIをインポート

"""
[ Blender Scene ]
    |
    |--- create_emission_material() --> [ Create Emission Material ]
    |                                     (Create material with emission node)
    |
    └--- apply_emission_material_to_text() --> [ Apply Material to Text ]
                                                (Add emission material to text object)

create_emission_material: 白色で発光する新しいマテリアルを作成し、エミッションノードを設定します。このマテリアルは、オブジェクトがレンダリング時に発光するようにします。
apply_emission_material_to_text: 作成した発光マテリアルをテキストオブジェクトに適用します。これにより、テキストがシーン内で光るようになります。

"""

def create_emission_material():
    # 発光マテリアルを作成
    mat = bpy.data.materials.new(name="EmissionMaterial")  # 新しいマテリアルを作成
    mat.use_nodes = True  # ノードを使用するように設定
    nodes = mat.node_tree.nodes
    nodes.clear()  # 既存のノードをクリア

    # エミッションノードを作成
    emission = nodes.new(type='ShaderNodeEmission')
    emission.inputs[0].default_value = (1, 1, 1, 1)  # 白色を設定
    emission.inputs[1].default_value = 5.0  # 強度を設定

    # 出力ノードを作成
    output = nodes.new(type='ShaderNodeOutputMaterial')

    # エミッションノードと出力ノードを接続
    links = mat.node_tree.links
    links.new(emission.outputs[0], output.inputs[0])

    return mat  # 作成したマテリアルを返す

def apply_emission_material_to_text(text_obj):
    # テキストオブジェクトに発光マテリアルを適用
    emission_mat = create_emission_material()  # 発光マテリアルを作成
    text_obj.data.materials.append(emission_mat)  # テキストオブジェクトにマテリアルを追加

rendering.py


import bpy  # Blender Python APIをインポート

"""
[ Blender Scene ]
    |
    |--- save_and_render() ----> [ Save Scene ]
    |                             (Save to specified path)
    |
    └---> [ Render Scene ]
          (Render to specified path)

シーンの保存: 指定されたパスがあれば、現在のBlenderシーンをそのパスに保存します。
シーンのレンダリング: 指定されたパスがあれば、現在のシーンをそのパスにレンダリングし、画像として出力します。
"""

def save_and_render(scene, save_path, render_path):
    # シーンを保存し、レンダリングする関数

    if save_path:
        # シーンを指定されたパスに保存する
        bpy.ops.wm.save_as_mainfile(filepath=save_path)

    if render_path:
        # シーンを指定されたパスにレンダリングする
        scene.render.filepath = render_path
        bpy.ops.render.render(write_still=True)  # 静止画としてレンダリング

scene_setup.py


import bpy  # Blender Python APIをインポート
from helpers import create_text_object  # テキストオブジェクト作成関数をインポート
from materials import apply_emission_material_to_text  # エミッションマテリアル適用関数をインポート

"""
[ Blender Scene ]
    |
    |--- setup_scene() ------------------------> [ Configure Scene ]
    |                                             (Set resolution, rendering engine, add text object)
    |
    |--- create_text_object() --> [ Create Text Object ]
    |
    |--- apply_emission_material_to_text() ----> [ Apply Emission Material to Text ]
    |
    |--- configure_camera() --------------------> [ Configure Camera ]
    |                                             (Set camera data and location)
    |
    └--- configure_lighting() ------------------> [ Configure Lighting ]
                                                  (Set lighting data and location)

setup_scene: シーンの解像度、レンダリングエンジン、ブルーム効果を設定し、テキストオブジェクトをシーンに追加します。
create_text_object: 指定されたテキストとフォントでテキストオブジェクトを作成します。
apply_emission_material_to_text: テキストオブジェクトにエミッションマテリアルを適用し、レンダリング時にテキストが発光するようにします。
configure_camera: シーンにカメラを配置し、位置を設定します。
configure_lighting: シーンに照明を配置し、位置と強度を設定します。

"""

def setup_scene(scene, image_path, font_path, text):
    # シーンの基本設定を行う関数
    scene.render.resolution_x = 1080  # 横解像度を設定
    scene.render.resolution_y = 1920  # 縦解像度を設定
    scene.render.engine = 'BLENDER_EEVEE'  # レンダリングエンジンをEeveeに設定
    scene.eevee.use_bloom = True  # ブルーム(光の輝き)効果を有効化

    # テキストオブジェクトを作成し、シーンに追加
    text_obj = create_text_object(text, font_path)
    scene.collection.objects.link(text_obj)

    # テキストオブジェクトにエミッションマテリアルを適用
    apply_emission_material_to_text(text_obj)

def configure_camera(scene):
    # カメラの設定を行う関数
    cam_data = bpy.data.cameras.new("Camera")  # カメラデータを新規作成
    cam_obj = bpy.data.objects.new("Camera", cam_data)  # カメラオブジェクトを新規作成
    scene.collection.objects.link(cam_obj)  # シーンにカメラをリンク
    scene.camera = cam_obj  # シーンのメインカメラを設定
    cam_obj.location = (0.0, 0.0, 14.0)  # カメラの位置を設定

def configure_lighting(scene):
    # 照明の設定を行う関数
    light_data = bpy.data.lights.new("Light", 'SUN')  # 照明データを新規作成(太陽光)
    light_obj = bpy.data.objects.new("Light", light_data)  # 照明オブジェクトを新規作成
    scene.collection.objects.link(light_obj)  # シーンに照明をリンク
    light_obj.location = (2.0, 2.0, 5.0)  # 照明の位置を設定
    light_obj.data.energy = 5.0  # 照明の強度を設定

リポジトリ

GitHub - Sunwood-ai-labs/VideoPortraitMaker
Contribute to Sunwood-ai-labs/VideoPortraitMaker development by creating an account on GitHub.

参考サイト

Blenderのpythonテンプレートを読み解く その2(background_job.py) - MRが楽しい
本日は Blender の小ネタ枠です。 Blenderのpythonテンプレートを読み解いて、どんな機能を持つテンプレートなのか確認します。 今回は「background_job」テンプレートです。 pythonテンプレートの利用方法 ビューを開き、メニューから テンプレート -> python を開きます。 様々な...
Pythonスクリプトでレンダリング|PianoMusic
 最近、Blenderでレンダリングを手動で行っていて枚数が多くなってくるとあまりにも面倒くさかった。そこで、Pythonスクリプトで自動化(プログラミングで処理)できないかな調べて実際にやってみたので忘れないうちに記録として... Pythonスクリプト  今回はパノラマ画像を環境マップとして読み込んでレンダリン...

コメント

タイトルとURLをコピーしました