夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

Blenderでレンダリング時に非表示になっているオブジェクトをすべてレンダリング対象外にする

本日はBlenderPython枠です。

Blenderではビューポート上でオブジェクトを非表示にすることができますが、別の設定としてレンダリング対象から外すものがあり、例えばビューポート上では非表示で見えなくてもレンダリング時にレンダリング対象としてレンダリングさせるということができます。

これは筆者だけかもしれないのですが、オブジェクトを非表示にしてレンダリング対象になったままレンダリングしてしまうことでレンダリング後に想定していないオブジェクトが表示されてしまうということがありました。

レンダリングには一定の時間がかかるため、朝起きて発狂しかけたことがあります。

そこで今回はレンダリング時に非表示になっているオブジェクトをすべて一時的にレンダリング対象外にするPythonスクリプトを書いていきます。

Pythonを使用したレンダリングの処理

レンダリングを行う際に自動的に処理を開始してほしいのでまずはレンダリングボタンを押した際にレンダリング前にイベントを取得できるか調べていきます

結論から書くとデフォルトのレンダリング方法で処理を途中に挟むのはBlender自体をオーバラップする形になり難しいです。

そのため今回は独自のアドオンとしてレンダリングボタンを作る手法で行っていきます。

pythonコードでBlenderレンダリングを行う処理は次のようになります。

import bpy

# レンダリングの実行
bpy.ops.render.render(write_still=True)

コードを実行すると通常のレンダリング同様にウィンドウが開きます。

つまりこの処理が実行された際にbpy.ops.render.render()を実行する前に処理を挟むことで非表示になっているオブジェクトをすべてレンダリング対象外にすることはできそうです。

例えば次のように実装することでレンダリング直前にログを出力できます。

import bpy

def my_callback(scene):
    # レンダリングが始まる前に実行されるコードをここに書く
    print("レンダリングが始まる前のイベントです")

# コールバックを登録
bpy.app.handlers.render_pre.append(my_callback)

# レンダリングの実行
bpy.ops.render.render(write_still=True)

# コールバックを削除
bpy.app.handlers.render_pre.remove(my_callback)

〇すべてのオブジェクトから非表示になっているオブジェクトを取得する

次にすべてのオブジェクトから非表示になっているオブジェクトを一覧取得する実装を行います。

コードは次のようになります。

import bpy

def log_hidden_render_objects():
    # 現在のアクティブなシーンを取得
    scene = bpy.context.scene

    # シーン内のすべてのコレクションを取得
    collections = bpy.data.collections

    # 非表示かつレンダリング対象のオブジェクトを格納するリスト
    hidden_render_objects = []

    # 各コレクション内の非表示かつレンダリング対象のオブジェクトを取得
    for collection in collections:
        for obj in collection.all_objects:
            if not obj.visible_get() and obj.hide_render:
                hidden_render_objects.append(obj.name)

    # ログに非表示かつレンダリング対象のオブジェクトを出力
    if hidden_render_objects:
        print("非表示かつレンダリング対象のオブジェクト:")
        for obj_name in hidden_render_objects:
            print(obj_name)
    else:
        print("非表示かつレンダリング対象のオブジェクトはありません。")

# ログに非表示かつレンダリング対象のオブジェクトを出力
log_hidden_render_objects()

if not obj.visible_get():によって現在searchしているオブジェクトが非表示であるかどうかを調べることができます。

 また'not obj.hide_render:'を条件に追加しこれによって非表示勝レンダリング対象のオブジェクトを含めています。

obj.hide_renderレンダリング対象外のオブジェクトを検索します。

 以上で条件が整いました。

Blenderレンダリング時に非表示になっているオブジェクトをすべてレンダリング対象外にする

割き二つの実装を組み合わせると次のようになります。

import bpy



def hidden_render_objects():
    # 現在のアクティブなシーンを取得
    scene = bpy.context.scene

    # シーン内のすべてのコレクションを取得
    collections = bpy.data.collections

    # 非表示かつレンダリング対象のオブジェクトを格納するリスト
    hidden_render_objects = []

    for collection in collections:
        for obj in collection.all_objects:
            if not obj.visible_get() and not obj.hide_render:
                hidden_render_objects.append(obj)

    if hidden_render_objects:
        for obj in hidden_render_objects:
            # レンダリング対象外に設定
            obj.hide_render = True
            print(f"{obj.name} をレンダリング対象外に設定しました。")
    else:
        print("非表示かつレンダリング対象のオブジェクトはありません。")

# ログに非表示かつレンダリング対象のオブジェクトを出力
hidden_render_objects()

# レンダリングの実行
bpy.ops.render.render(write_still=True)

〇動作確認

今回は次のようにキューブを二つ配置しました。

当然ですがこのままレンダリングすると次のように2つのキューブが発生します。

次に今回作成したコードベースで実行すると次のようにキューブが1つになりBlenderのビューポート同様にレンダリングが行われていることを確認できました。

本日は以上です。