単純な画像ベイク機能をアドオンにしてみる

Blender Advent Calendar 2020 の23日として投稿します。
https://qiita.com/advent-calendar/2020/blender

ゲーム用モデルやVRchatアバターのテクスチャを作るのに
シェーダーで作ったテクスチャをベイクしたり　UVを整理した画像にベイクしたいという用途があるのか
春頃からBlenderでのテクスチャのベイクに関する話題を見かけることが増えたように思います。

私もとある仕事で　ボタン一つ操作でベイク画像を用意する必要がある案件に遭遇したので
目的のベイク画像を作成するアドオンを作成しました。

画像エディッタに表示しているイメージに、現在アクティブにしているUVを利用して
ディフューズカラーのをベイクします。

``` py:ySympleBekeImage.py
import bpy
bl_info = {
    "name": "Simple Bake Image",
    "description": "UVエディッタで表示中の画像にオブジェクトの色をベイク",
    "author": "Yukimi",
    "version": (0,9),
    "blender": (2, 80, 0),
    "location": "material",
    "warning": "",
    "wiki_url": "",
    "tracker_url": "http://yukimi-blend.blogspot.jp/",
    "category": "material"}


# ベイク用のノードの作成
def criete_bake_terget(mat, image, uv_layer):
    node_tree = mat.node_tree
    img_node = node_tree.nodes.new("ShaderNodeTexImage")
    img_node.image = image
    uv_node = node_tree.nodes.new("ShaderNodeUVMap")
    uv_node.uv_map = uv_layer.name
    node_tree.links.new( uv_node.outputs[0], img_node.inputs[0] )
    #ベイク対象はアクティブなノード
    node_tree.nodes.active = img_node
    return(img_node, uv_node)
# ベイク用マテリアルの消去
def crean_beke_terget(beke_nodes):
    for m in beke_nodes:
        mat = m[0]
        img_node = m[1][0]
        uv_node = m[1][1]
        mat.node_tree.nodes.remove(img_node)
        mat.node_tree.nodes.remove(uv_node)
# ベイク
def Simple_bake(scene):
    # 現在のレンダリング設定の退避
    ref_engine = scene.render.engine
    scene.render.engine = 'CYCLES'
    # 現在のサンプル数の退避
    ref_sampkung = scene.cycles.samples
    scene.cycles.samples = 8
    #ベイク動作
    bpy.ops.object.bake(type='DIFFUSE', pass_filter={'COLOR',}, use_clear=False)
    # 放射ノードの出力を使う場合はこちらをコメントアウト
    #bpy.ops.object.bake(type='EMIT', use_clear=False)
    # サンプリング数を元に
    scene.cycles.samples = ref_sampkung
    # レンダリングエンジンを元に
    scene.render.engine = ref_engine

def bake_func(context):
    scene = context.scene
    obj = bpy.context.active_object
    # アクティブオブジェクトがメッシュか？
    if obj.type != "MESH": return()
    if context.space_data.mode != 'UV': return()
    # ビューで表示中の画像の取得
    image = context.space_data.image
    # UVの取得
    uv_layer = obj.data.uv_layers[obj.data.uv_layers.active_index]
    # 個々のマテリアルでループ
    # （複数マテリアルがある場合　それぞれにベイク用ノードが設定されている必要あり）  
    bake_nodes = []
    for slot in  obj.material_slots:
        mat = slot.material
        nodes = criete_bake_terget(mat, image, uv_layer)
        bake_nodes.append([mat,nodes])
    #ディフューズカラーのみベイク
    Simple_bake(scene)
    #ベイクに使用したノードをクリーンナップ
    crean_beke_terget(bake_nodes)
    
    
###################################################
class bake_OT_diffusecolor(bpy.types.Operator):
	'''bake diffuse coor to display Image'''
	bl_idname = "action.bake_diffuse"
	bl_label = "bake diffuse coor to display Image"
	def execute(self, context):
		bake_func(context)
		return {'FINISHED'}


def menu_func(self, context):
	self.layout.operator("action.bake_diffuse", 
		text="カラーを表示画像にベイク" )

def register():
    bpy.utils.register_class(bake_OT_diffusecolor)
    bpy.types.IMAGE_MT_image.prepend(menu_func)

def unregister():
    bpy.types.IMAGE_MT_image.remove(menu_func)
    bpy.utils.unregister_class(bake_OT_diffusecolor)

if __name__ == "__main__":
    register()
##########################################################
```


インストールすると　画像メニューに「カラーを表示画像にベイク」という項目が追加されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/5554ac80-84ce-ae2d-f2e9-57138aee70e0.png)

単純にベイクするだけならTexToolsにあるベイク機能等でもいいのですが
複数のオブジェクトのマテリアルの画像をまとめる　といった作業の場合には使えないですし
UVの指定やベイク対象の指定等の作業は煩雑ですよね。

Simple_bake関数を書き換えることで　現場に合った画像を出力するのに使えるのではないかと思います
今回はディフューズカラーのみなので　サンプリング数を下げることでベイク速度を上げています。
また、複数のオブジェクトにまたがってベイクを調整する時のために　既存の画像はクリアしない設定にしています。

何かしら役に立てば幸いです。