検証 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():
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']
)