検証 Blender Version : 3.2.1
コマンドラインからスクリプトを実行する
sample.blendを起動し、sample.pyを実行する例です
"C:\Program Files\Blender Foundation\Blender 3.2\blender.exe" sample.blend --python sample.py
import bpy def _override_context(): idx = bpy.context.window_manager.windows[:].index(bpy.context.window) window = bpy.context.window_manager.windows[idx] screen = window.screen area = [ area for area in screen.areas if area.type == 'VIEW_3D' ][0] region = [ region for region in area.regions if region.type == 'WINDOW' ][0] return bpy.context.temp_override(window=window, area=area, region=region) if __name__ == '__main__': with _override_context(): # ここにスクリプトを記述 # 以下はCubeオブジェクトのUVをスケールする例 bpy.data.objects['Cube'].select_set(True) bpy.ops.object.mode_set(mode='EDIT') bpy.context.area.ui_type = 'UV' bpy.context.scene.tool_settings.use_uv_select_sync = True bpy.ops.uv.select_all(action='SELECT') bpy.ops.transform.resize(value=(0.5, 1, 1))
Context Overrideについて
コマンドラインから実行するとbpy.context.areaなどがNoneなので、
それらを使用する場合はbpy.context.temp_overrideが必要になります。
参考 : https://stackoverflow.com/questions/70958391/execute-script-after-blender-is-fully-loaded
オブジェクトを結合する
オブジェクトCube, Cube.001を結合してCube_Joinにリネームする例です。
import bpy def join_objects(join_name, object_names): bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_all(action='DESELECT') for object_name in object_names: bpy.data.objects[object_name].select_set(True) bpy.context.view_layer.objects.active = bpy.data.objects[object_names[0]] bpy.ops.object.join() bpy.data.objects[object_names[0]].name = join_name if __name__ == '__main__': join_objects('Cube_Join', ['Cube', 'Cube.001'])
マテリアルを結合して1つのマテリアルにする
オブジェクトCubeのマテリアルMaterial, Material.001(に割り当てられた面)を
結合してMaterial_Joinにリネームする例です。
import bpy def _set_active_material_slot(object, material): for i, material_slot in enumerate(object.material_slots): if material is material_slot.material: object.active_material_index = i def join_materials(object_name, join_name, material_names): object = bpy.data.objects[object_name] object.select_set(True) bpy.ops.object.mode_set(mode='EDIT') materials = bpy.data.materials bpy.ops.mesh.select_all(action='DESELECT') for material_name in material_names: material = materials[material_name] _set_active_material_slot(object, material) bpy.ops.object.material_slot_select() material = materials[material_name] _set_active_material_slot(object, material) bpy.ops.object.material_slot_assign() bpy.ops.object.mode_set(mode='OBJECT') for material_name in material_names[1:]: material = materials[material_name] _set_active_material_slot(object, material) bpy.ops.object.material_slot_remove() materials[material_names[0]].name = join_name if __name__ == '__main__': join_materials('Cube', 'Material_Join', ['Material', 'Material.001'])
マテリアルのテクスチャを差し替える
マテリアルMaterialのテクスチャをtexture2.pngに差し替える例です。
import bpy def _load_image(image_path, image_name): if image_name not in bpy.data.images: image = bpy.data.images.load(image_path) image.name = image_name def relink_material_texture(material_name, image_path): image_name = bpy.path.basename(image_path) _load_image(image_path, image_name) material = bpy.data.materials[material_name] node = [link.from_node for link in material.node_tree.links if ( link.from_node.type == 'TEX_IMAGE' and link.to_node.type == 'BSDF_PRINCIPLED' and link.from_socket.name == 'Color' and link.to_socket.name == 'Base Color' ) ][0] node.image = bpy.data.images[image_name] if __name__ == '__main__': relink_material_texture('Material', '//texture2.png')
UVを結合して1つのテクスチャにする
オブジェクトPlane, Plane.001, Plane.002のUV(512x512pixel)を変形し、
オブジェクト・マテリアルをPlane_Join, Material_Joinに結合し、
テクスチャをtexture_join.png(1024x1024pixel)に差し替える例です。
import bpy import numpy as np def transform_uv(object_name, join_image_name, src_image_name, pos): """ UVを変形する pos : 左上を原点としたイメージの位置(pixel) """ bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_all(action='DESELECT') object = bpy.data.objects[object_name] object.select_set(True) bpy.context.view_layer.objects.active = object bpy.ops.object.mode_set(mode='EDIT') bpy.context.area.ui_type = 'UV' image_editor = bpy.context.space_data bpy.context.scene.tool_settings.use_uv_select_sync = True join_image = bpy.data.images[join_image_name] join_image_size = np.array(join_image.size[:]) src_image = bpy.data.images[src_image_name] src_image_size = np.array(src_image.size[:]) bpy.ops.uv.select_all(action='SELECT') image_editor.cursor_location = [0, 1] image_editor.pivot_point = 'CURSOR' resize = src_image_size / join_image_size bpy.ops.transform.resize( value=(resize[0], resize[1], 1), orient_type='GLOBAL', orient_matrix=np.eye(3), constraint_axis=(True, True, True) ) translate = np.array(pos) / join_image_size bpy.ops.transform.translate( value=(translate[0], -translate[1], 0), orient_matrix=np.eye(3), constraint_axis=(True, True, True) ) infos = { 'join_object_name' : 'Plane_Join', 'join_material_name' : 'Material_Join', 'join_image_name' : 'texture_join.png', 'objects' : [ { 'name' : 'Plane', 'image' : 'texture1.png', 'material' : 'Material', 'pos' : (0, 0), }, { 'name' : 'Plane.001', 'image' : 'texture2.png', 'material' : 'Material.001', 'pos' : (512, 0), }, { 'name' : 'Plane.002', 'image' : 'texture3.png', 'material' : 'Material.002', 'pos' : (0, 512), }, ] } if __name__ == '__main__': for info in infos['objects']: transform_uv( info['name'], infos['join_image_name'], info['image'], info['pos'] ) join_objects( infos['join_object_name'], [info['name'] for info in infos['objects']] ) join_materials( infos['join_object_name'], infos['join_material_name'], [info['material'] for info in infos['objects']] ) relink_material_texture( infos['join_material_name'], '//'+infos['join_image_name'] )