Blender 4.0でPython APIを使用してフォント指定で日本語文字を表示する方法

## はじめに


この記事では、Blender 4.0でPython APIを使用してフォント指定で日本語文字を表示する方法する手順を説明します。このプロセスは、コマンドラインからBlenderを操作し、自動化タスクを実行する際に役立ちます。

---

こちらの記事もおすすめ

https://hamaruki.com/displaying-characters-using-python-api-in-blender-4-0/

https://hamaruki.com/generate-3d-models-from-images-using-wonder3d/

https://hamaruki.com/how-to-create-luminous-object-animations-with-blender-4-0-even-for-beginners/



## 必要なツール

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

## クリプトの準備

まず、Blenderをバックグラウンドで実行し、テキストオブジェクト、カメラ、ライトを作成してレンダリングするスクリプトを準備します。以下のスクリプトをテキストエディタにコピーし、`background_job.py`という名前で保存します。

```python

# Blenderをコマンドラインからバックグラウンドモードで実行するためのスクリプト例。
# テキストオブジェクト、カメラ、ライトを作成し、レンダリングまたは保存します。
# スクリプトにコマンドラインオプションを解析する方法も示されています。
# 使用例:
#  blender --background --factory-startup --python $HOME/background_job.py -- \
#          --text="Hello World" \
#          --render="/tmp/hello" \
#          --save="/tmp/hello.blend"
# '--factory-startup' はユーザーのデフォルト設定が自動シーン生成に干渉しないように使用されます。
# '--' はBlenderがその後の引数を無視し、Pythonがそれらを使用できるようにします。
# 詳細は blender --help を参照。

import bpy  # Blender Python API
import os   # OS関連の操作のためのモジュール

def example_function(text, save_path, render_path, font_path):
    # 既存のオブジェクトをクリアします。
    bpy.ops.wm.read_factory_settings(use_empty=True)

    scene = bpy.context.scene  # 現在のシーンを取得

    # レンダリングエンジンをEeveeに設定し、ブルーム効果を有効化
    bpy.context.scene.render.engine = 'BLENDER_EEVEE'
    bpy.context.scene.eevee.use_bloom = True

    # テキストオブジェクトの作成
    txt_data = bpy.data.curves.new(name="MyText", type='FONT')
    
    # 指定されたフォントをロード
    if os.path.exists(font_path):
        fnt = bpy.data.fonts.load(font_path)  # フォントファイルのロード
        txt_data.font = fnt
    else:
        print(f"Font file not found: {font_path}")
    
    txt_ob = bpy.data.objects.new(name="MyText", object_data=txt_data)
    scene.collection.objects.link(txt_ob)  # シーンにテキストオブジェクトをリンク
    txt_data.body = text  # テキストの内容を設定
    txt_data.align_x = 'CENTER'  # テキストの中央揃え

    # テキストマテリアルの設定（発光）
    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
    link = links.new(emission.outputs[0], output.inputs[0])
    txt_ob.data.materials.append(mat)  # テキストにマテリアルを適用

    # カメラの設定
    cam_data = bpy.data.cameras.new("MyCam")
    cam_ob = bpy.data.objects.new(name="MyCam", object_data=cam_data)
    scene.collection.objects.link(cam_ob)  # シーンにカメラをリンク
    scene.camera = cam_ob
    cam_ob.location = 0.0, 0.0, 10.0  # カメラの位置

    # 太陽光の設定
    light_data = bpy.data.lights.new("MyLight", 'SUN')
    light_ob = bpy.data.objects.new(name="MyLight", object_data=light_data)
    scene.collection.objects.link(light_ob)  # シーンにライトをリンク
    light_ob.location = 2.0, 2.0, 5.0  # ライトの位置
    light_ob.data.energy = 5.0  # ライトの強度を調整

    bpy.context.view_layer.update()  # ビューレイヤーを更新

    # ファイルの保存とレンダリングのオプション
    if save_path:
        bpy.ops.wm.save_as_mainfile(filepath=save_path)
    if render_path:
        render = scene.render
        render.use_file_extension = True
        render.filepath = render_path
        bpy.ops.render.render(write_still=True)  # 静止画のレンダリング

def main():
    import sys       # コマンドライン引数を取得するため
    import argparse  # オプションを解析するため

    argv = sys.argv

    if "--" not in argv:
        argv = []  # 引数がない場合は空のリスト
    else:
        argv = argv[argv.index("--") + 1:]  # "--" の後の引数を取得

    usage_text = (
        "このスクリプトでBlenderをバックグラウンドモードで実行:"
        "  blender --background --python " + __file__ + " -- [options]"
    )

    parser = argparse.ArgumentParser(description=usage_text)
    parser.add_argument("-t", "--text", dest="text", type=str, default="ハローワールド",
                        help="画像をレンダリングするためのテキスト")
    parser.add_argument("-s", "--save", dest="save_path", metavar='FILE', default="/tmp/hello.blend",
                        help="生成したファイルを指定したパスに保存")
    parser.add_argument("-r", "--render", dest="render_path", metavar='FILE', default="/tmp/hello3",
                        help="指定したパスに画像をレンダリング")
    parser.add_argument("-f", "--font", dest="font_path", type=str, 
                        default="C:\\Windows\\Fonts\\meiryob.ttc",
                        help="テキストのレンダリングに使用するフォントファイルへのパス")

    print(">>> args")
    args = parser.parse_args(argv)  # 引数を解析

    print(args)

    if not args.text:
        print("Error: --text=\"some string\" argument not given, aborting.")
        parser.print_help()
        return

    # フォントパスを使用して関数を実行
    example_function(args.text, args.save_path, args.render_path, args.font_path)

    print("Batch job finished, exiting")

if __name__ == "__main__":
    main()  # スクリプトが直接実行された場合にmain関数を呼び出す

```

![](https://hamaruki.com/wp-content/uploads/2023/12/hello3-1024x576.png)


## リポジトリ

https://github.com/Sunwood-ai-labs/VideoPortraitMaker/tree/main

## 参考サイト

https://bluebirdofoz.hatenablog.com/entry/2020/06/19/002435

https://note.com/piano_music/n/n9dce46416492