1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Blender 4.0でPython APIを使用して文字を表示してレンダリングする方法

Last updated at Posted at 2023-12-02

はじめに

この記事では、Blender 4.0でPython APIを使用して文字を表示し、レンダリングする手順を説明します。このプロセスは、コマンドラインからBlenderを操作し、自動化タスクを実行する際に役立ちます。


こちらの記事もおすすめ

必要なツール

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

クリプトの準備

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

# This script is an example of how you can run blender from the command line
# (in background mode with no interface) to automate tasks, in this example it
# creates a text object, camera and light, then renders and/or saves it.
# This example also shows how you can parse command line options to scripts.
#
# Example usage for this test.
#  blender --background --factory-startup --python $HOME/background_job.py -- \
#          --text="Hello World" \
#          --render="/tmp/hello" \
#          --save="/tmp/hello.blend"
#
# Notice:
# '--factory-startup' is used to avoid the user default settings from
#                     interfering with automated scene generation.
#
# '--' causes blender to ignore all following arguments so python can use them.
#
# See blender --help for details.


import bpy


def example_function(text, save_path, render_path):
    # Clear existing objects.
    bpy.ops.wm.read_factory_settings(use_empty=True)

    scene = bpy.context.scene
    
    # Set the render engine to Eevee
    bpy.context.scene.render.engine = 'BLENDER_EEVEE'
    bpy.context.scene.eevee.use_bloom = True

    # Text Object
    txt_data = bpy.data.curves.new(name="MyText", type='FONT')
    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'

    # Text Material (Emission)
    mat = bpy.data.materials.new(name="EmissionMaterial")
    mat.use_nodes = True
    nodes = mat.node_tree.nodes
    nodes.clear()  # clear all the nodes
    emission = nodes.new(type='ShaderNodeEmission')
    emission.inputs[0].default_value = (1, 1, 1, 1)  # white color
    emission.inputs[1].default_value = 5.0  # strength
    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)

    # Camera
    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

    # Sun Light
    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  # adjust the energy for desired brightness

    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 create_simple_scene(save_path, render_path):
    # Clear existing objects
    bpy.ops.wm.read_factory_settings(use_empty=True)

    scene = bpy.context.scene

    # Create a simple cube
    bpy.ops.mesh.primitive_cube_add(size=2)
    cube = bpy.context.object

    # Camera
    cam_data = bpy.data.cameras.new("Camera")
    cam_ob = bpy.data.objects.new("Camera", cam_data)
    scene.collection.objects.link(cam_ob)
    scene.camera = cam_ob
    cam_ob.location = (5, -5, 5)
    cam_ob.rotation_euler = (0.785398, 0, 0.785398)

    # Light
    light_data = bpy.data.lights.new(name="Light", type='POINT')
    light_ob = bpy.data.objects.new("Light", light_data)
    scene.collection.objects.link(light_ob)
    light_ob.location = (0, 0, 5)

    # Update the scene
    bpy.context.view_layer.update()

    # Save and Render
    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       # to get command line args
    import argparse  # to parse options for us and print a nice help message

    # get the args passed to blender after "--", all of which are ignored by
    # blender so scripts may receive their own arguments
    argv = sys.argv

    if "--" not in argv:
        argv = []  # as if no args are passed
    else:
        argv = argv[argv.index("--") + 1:]  # get all args after "--"

    # When --help or no args are given, print this help
    usage_text = (
        "Run blender in background mode with this script:"
        "  blender --background --python " + __file__ + " -- [options]"
    )

    parser = argparse.ArgumentParser(description=usage_text)

    # Example utility, add some text and renders or saves it (with options)
    # Possible types are: string, int, long, choice, float and complex.
    parser.add_argument(
        "-t", "--text", dest="text", type=str, default="Hello World",
        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/hello2",
        help="Render an image to the specified path",
    )
    
    print(">>> args")
    args = parser.parse_args(argv)  # In this example we won't use the args
    
    print(args)

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

    # Run the example function
    example_function(args.text, args.save_path, args.render_path)
    #create_simple_scene(args.save_path, args.render_path)

    print("Batch job finished, exiting")
    print("batch job finished, exiting")


if __name__ == "__main__":
    main()

スクリプトの解説

スクリプトは大きく分けて3つの部分から構成されます。

example_function

この関数は、テキストオブジェクトを作成し、EeveeレンダーエンジンでBloom効果を有効にして、シーンをレンダリングします。

  • テキストオブジェクトの作成
  • エミッションマテリアルの追加
  • カメラとサンライトの設定
  • レンダリングと保存の設定

main

この関数は、コマンドライン引数を解析し、上記のexample_functionを実行します。

  • 引数解析
  • example_functionの呼び出し

スクリプトの実行部

最後に、スクリプトが直接実行された場合にmain関数を呼び出します。

コマンドラインからの実行

Blenderをインストールしたディレクトリに移動し、以下のコマンドを実行します。

blender --background --factory-startup --python /path/to/background_job.py -- --text="Your Text" --render="/path/to/render.png" --save="/path/to/save.blend"
  • --background はBlenderをバックグラウンドモードで起動します。
  • --factory-startup はユーザー設定を無視して、デフォルト設定でBlenderを開始します。
  • --python はPythonスクリプトを指定します。
  • --text, --render, --save はスクリプトに渡す引数です。

結果の確認

コマンドを実行した後、指定したレンダーパスに画像ファイルが、保存パスにBlenderファイルが生成されていることを確認します。

まとめ

この記事では、BlenderのPython APIを使用して、テキストを含むシンプルな3Dシーンを自動的に作成し、レンダリングする方法を紹介しました。この技術は、3Dグラフィックスの自動化やバッチ処理に非常に有効です。今後は、Twitter用に作成した動画をインスタグラムやTiktok用に変換するスクリプトを作成していきます。

リポジトリ

参考サイト

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?