夜風のMixedReality

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

Blenderでレンダリング設定を書き換えて自動的にベイクを行う

本日はBlender枠です。

〇環境

・Blender4.1

・Windows11PC

Pythonスクリプトからベイクを行う

先日Pythonスクリプト経由でレンダリング設定を書き換えました。

redhologerbera.hatenablog.com

本日はCyclesエンジンでのみ実行可能なベイクをPythonベースで行っていきます。

〇ベイク用のライト設定

今回はスキャンやAIが作成したようなテクスチャをベイクする用途で使用するため、UV球に放射シェーダーを使用したマテリアルのライトオブジェクトを作成します。

redhologerbera.hatenablog.com

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

# 現在のアクティブオブジェクトを取得(ベイク対象)
obj = bpy.context.view_layer.objects.active
 
if obj and obj.type == 'MESH':
    # ベイク前にライトとして使用するUV球を作成
    bpy.ops.object.select_all(action='DESELECT')#すべて選択解除
    bpy.ops.mesh.primitive_uv_sphere_add(radius=10, location=(0, 0, 0))
    light_sphere = bpy.context.active_object #スケール10でUV球を作成
 
    # UV球の法線を反転
    bpy.ops.object.mode_set(mode='EDIT') #一度編集モードに設定
    bpy.ops.mesh.normals_make_consistent(inside=True) #ノーマルの反転を実行
    bpy.ops.object.mode_set(mode='OBJECT') #オブジェクトモードへ変更
 
    # 放射シェーダーを持つマテリアルを作成してUV球に割り当て
    emission_material = bpy.data.materials.new(name="LightMaterial")
    emission_material.use_nodes = True #ノードを使用
    emission_nodes = emission_material.node_tree.nodes 
    emission_links = emission_material.node_tree.links 
 
    # 既存のノードをクリア
    for node in emission_nodes: 
        emission_nodes.remove(node)
 
    # 放射シェーダーとマテリアル出力ノードを作成
    emission_node = emission_nodes.new(type='ShaderNodeEmission')
    output_node = emission_nodes.new(type='ShaderNodeOutputMaterial')
 
    # ノードを接続
    emission_links.new(emission_node.outputs['Emission'], output_node.inputs['Surface'])
 
    # UV球にマテリアルを割り当て
    light_sphere.data.materials.append(emission_material)
 

以上のコードでライトオブジェクトを作成しています。

個々での肝はbpy.ops.mesh.normals_make_consistent(inside=True)です。

この一文で対象の法線を反転させています。

bpy.data.objects.remove(light_sphere)をベイク後に実行することでこのUV球を削除することができます。

〇ベイク処理

ベイク処理もPythonコードで実行することができます。

   # ベイクの設定
    bpy.context.scene.render.bake.use_selected_to_active = False
    bpy.context.scene.render.bake.target = 'IMAGE_TEXTURES'
    bpy.context.scene.render.bake.use_clear = True
    bpy.context.scene.render.bake.margin = 16
 
    # ベイクを実行
    bpy.context.view_layer.objects.active = obj
    bpy.ops.object.bake(type='COMBINED')
 

これによってベイクが行われます。

〇コード全文

使い方としてはオブジェクトモードでオブジェクトを選択、コードを実行するだけで頂点カラーをベイクして、テクスチャとして使用することができます。

import bpy
 
# レンダーエンジンをCyclesに設定
bpy.context.scene.render.engine = 'CYCLES'
 
# デバイスをGPUに設定(OptiX)
bpy.context.scene.cycles.device = 'GPU'
bpy.context.preferences.addons['cycles'].preferences.compute_device_type = 'OPTIX'
 
# ライトパス設定:間接照明の制限を0に設定
bpy.context.scene.cycles.sample_clamp_indirect = 0.0
 
# サンプリング数の設定
bpy.context.scene.cycles.samples = 128  # レンダー時のサンプリング数
bpy.context.scene.cycles.preview_samples = 64  # ビューポートのサンプリング数
 
# 現在のアクティブオブジェクトを取得
obj = bpy.context.view_layer.objects.active
 
if obj and obj.type == 'MESH':
    # ベイク前にライトとして使用するUV球を作成
    bpy.ops.object.select_all(action='DESELECT')
    bpy.ops.mesh.primitive_uv_sphere_add(radius=10, location=(0, 0, 0))
    light_sphere = bpy.context.active_object
 
    # UV球の法線を反転
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.normals_make_consistent(inside=True)
    bpy.ops.object.mode_set(mode='OBJECT')
 
    # 放射シェーダーを持つマテリアルを作成してUV球に割り当て
    emission_material = bpy.data.materials.new(name="LightMaterial")
    emission_material.use_nodes = True
    emission_nodes = emission_material.node_tree.nodes
    emission_links = emission_material.node_tree.links
 
    # 既存のノードをクリア
    for node in emission_nodes:
        emission_nodes.remove(node)
 
    # 放射シェーダーとマテリアル出力ノードを作成
    emission_node = emission_nodes.new(type='ShaderNodeEmission')
    output_node = emission_nodes.new(type='ShaderNodeOutputMaterial')
 
    # ノードを接続
    emission_links.new(emission_node.outputs['Emission'], output_node.inputs['Surface'])
 
    # UV球にマテリアルを割り当て
    light_sphere.data.materials.append(emission_material)
 
    # ベイク対象のオブジェクトを再選択
    bpy.ops.object.select_all(action='DESELECT')
    bpy.context.view_layer.objects.active = obj
    obj.select_set(True)
 
    # 現在のオブジェクトにマテリアルがあるか確認
    if len(obj.data.materials) > 0:
        material = obj.data.materials[0]
    else:
        material = bpy.data.materials.new(name="NewMaterial")
        obj.data.materials.append(material)
 
    # ノードを使用可能にする
    material.use_nodes = True
    nodes = material.node_tree.nodes
    links = material.node_tree.links
 
    # プリンシパルシェーダーを取得
    principled_shader_node = nodes.get('Principled BSDF')
 
    # カラー属性(頂点カラー)ノードを作成
    color_attribute_node = nodes.new(type='ShaderNodeVertexColor')
    color_attribute_node.location = (-300, 0)
 
    # カラー属性ノードをプリンシパルシェーダーのベースカラーに接続
    if principled_shader_node:
        links.new(color_attribute_node.outputs['Color'], principled_shader_node.inputs['Base Color'])
        print("頂点カラーをプリンシパルシェーダーのベースカラーに接続しました。")
    else:
        print("プリンシパルシェーダーが見つかりませんでした。")
 
    # 新しい画像テクスチャノードを作成
    tex_image_node = nodes.new(type='ShaderNodeTexImage')
    tex_image_node.location = (300, 0)
 
    # 新しい1024x1024の画像を作成し、BakeTextureという名前を付ける
    bake_image = bpy.data.images.new(name="BakeTexture", width=1024, height=1024)
    tex_image_node.image = bake_image
 
    # ベイクの設定
    bpy.context.scene.render.bake.use_selected_to_active = False
    bpy.context.scene.render.bake.target = 'IMAGE_TEXTURES'
    bpy.context.scene.render.bake.use_clear = True
    bpy.context.scene.render.bake.margin = 16
 
    # ベイクを実行
    bpy.context.view_layer.objects.active = obj
    bpy.ops.object.bake(type='COMBINED')
 
    # ベイクが完了したら、頂点カラーのノードを削除
    nodes.remove(color_attribute_node)
 
    # テクスチャをプリンシパルシェーダーのベースカラーに接続
    if principled_shader_node:
        links.new(tex_image_node.outputs['Color'], principled_shader_node.inputs['Base Color'])
        print("BakeTextureをプリンシパルシェーダーのベースカラーに接続しました。")
 
    # ライト用のUV球を削除
    bpy.data.objects.remove(light_sphere)
 
else:
    print("オブジェクトが選択されていないか、メッシュオブジェクトではありません。")