Blenderでシーン内のオブジェクトの置き換え

３Ｄモデルを作成していると
作業途中のデータを残した状態で作業して、別途出力用に整理したファイルを別途作成することがあるかと思います

Blenderでは特にモデファイア等で複数のオブジェクトを組み合わせたものから
モデファイアの適応や結合で最終的なオブジェクトに変換することも多いです。
そうした統合したモデルの微調整が必要になった場合、どういう手順でやっているでしょうか？
アペンドでモデリング用のファイルからデータを読み込むという方法もありますが　調整にいくつかの手順が必要です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/1d1f9467-70c4-ab2d-c9a9-29ef7491022f.png)

統合したファイルの中のデータを微調整したデータで置き換えるためのスクリプトを作成しました
Blender2.8用のスクリプトです。
（Blender2.7系もほぼ同じコードで動きますが調整の必要な箇所が多いのでまたの機会に）

```replace_obj.py
import bpy
import os
from bpy.props import StringProperty
from bpy_extras.io_utils import ImportHelper
#ファイルオープン　単独ファイルのみ
class IMPORT_OT_OBJ(bpy.types.Operator, ImportHelper):
    bl_idname = "replace_object.object"
    bl_description = 'Replece Object from selected file'
    bl_label = "replace object"
    filepath: StringProperty(
            name="input file",
            subtype='FILE_PATH'
            )
    filename_ext : ".blend"
    filter_glob: StringProperty(
            default="*.blend",
            options={'HIDDEN'},
            )
    def execute(self, context):  
        # インフォエディッタにファイル名を出力
        self.report({'INFO'},self.filepath)
        #今シーンで選択されているオブジェクト
        selected_objects = context.selected_objects
        #ファイル内の同名のオブジェクトのアペンド
        self.append_objects(selected_objects)
        return{'FINISHED'}
    def append_objects(self, objects):
        obj_name_list = [obj.name for obj in objects]
        blendfile = self.filepath
        # データの読み込み
        with bpy.data.libraries.load(blendfile, link=False) as (data_from, data_to):
            data_to.objects = [name for name in data_from.objects if name in obj_name_list]
            # （data_from.objectsは名前のリスト）
        read_data = data_to
        for i,ref_obj in enumerate(read_data.objects):
            if ref_obj is None:continue
            if ref_obj.type != objects[i].type:continue
            linked_objects = get_linked_objects(objects[i])
            for obj in linked_objects:
                replace_data(ref_obj, obj)

def get_linked_objects(ref_obj):
    datablock = ref_obj.data
    linked_objects = []
    for obj in bpy.data.objects:
        if obj.data == datablock:
            linked_objects.append(obj)
    return(linked_objects)

def replace_data(obj_from,obj_to):
    if obj_from.type == 'MESH':
        # 頂点グループの状態を読み込みオブジェクト合わせえる
        obj_to.vertex_groups.clear()
        for grope in obj_from.vertex_groups:
            obj_to.vertex_groups.new( name = grope.name )
        # Dataに付加されたマテリアルを選択オブジェクトに合わせる
        for i,mat in enumerate( obj_to.data.materials):
            obj_from.data.materials[i] = mat
    # 読み込みオブジェクトのデータを選択オブジェクトにリンク
    obj_to.data = obj_from.data


def register():
    bpy.utils.register_class(IMPORT_OT_OBJ)

def unregister():
    bpy.utils.unregister_class(IMPORT_OT_OBJ)

if __name__ == "__main__":
    register()
    # test call
    bpy.ops.replace_object.object('INVOKE_DEFAULT')
```

統合ファイル上で置き換えをしたいオブジェクトを選択して
スクリプトを実行するとファイル選択ダイアログが出ます
モデリング用のファイルを選択すると同じ名前のオブジェクトのメッシュデータで置き換えをします。

メッシュのデータを置き換える操作になるため
モデファイアやマテリアルは統合ファイルのものを使用します。

注意点として　モデリング等の調整でマテリアルや頂点グループの順序を変更しないでください。

まだまだテスト中のコードになるので
使い勝手等試していただけるとうれしいです。