本日はBlender枠です。
〇環境
・Blender4.1
・Windows11PC
〇Pythonスクリプトからベイクを行う
先日Pythonスクリプト経由でレンダリング設定を書き換えました。
本日はCyclesエンジンでのみ実行可能なベイクをPythonベースで行っていきます。
〇ベイク用のライト設定
今回はスキャンやAIが作成したようなテクスチャをベイクする用途で使用するため、UV球に放射シェーダーを使用したマテリアルのライトオブジェクトを作成します。
コードは次のようになります。
# 現在のアクティブオブジェクトを取得(ベイク対象)
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("オブジェクトが選択されていないか、メッシュオブジェクトではありません。")