Blender 4.1, Python ビル、自動車、動画

2020年に書いた記事「Blender 2.9, Python ビル、自動車、動画」を、blender 4.1.1で動作するように改訂しました。
なお途中の= KOI HONMACHI Map =の部分6行はJPEG画像（地図）を呼び出しているのでエラーが出る場合は消してください。

主な変更点は
(A)ビルの形状。cube使用。途中の2箇所　bpy.ops.mesh.primitive_cube_add(size=2　を　(size = 1と変更すると元の狙った形状にできた。
原因不明。blender 2.9からblender 4.1へのどこかで仕様変更があったかも。

(B)自動車移動 CAR movement で、bpy.context.scene.frame_current = 1 を bpy.context.scene.frame_set(frame_num)に。frame_numには適度に数字をパラパラと入れて。ホロモン氏「MRが楽しい」 の記事を参考に。

(C)自動車移動 CAR movement の部分は変数を変えながら5行ごとにダラダラ書いていたのをきちんとfor文の繰り返しに変えました。最初からこう書けばよかった話。
![uploading...0]()


```python:title.bph55

#bph55,  車体、地図建物。階段, 看板2枚　2020.10.28---2024.5.17
import bpy
import bmesh
import math
from math import radians
from mathutils import Matrix

#========= DELETE ALL mesh, light, camera, みな削除する2行 =========
for item in bpy.data.objects:
    bpy.data.objects.remove(item)

def hex_to_rgb( hex_value ): #=== hex color code to RGB
    b = (hex_value & 0xFF) / 255.0
    g = ((hex_value >> 8) & 0xFF) / 255.0
    r = ((hex_value >> 16) & 0xFF) / 255.0
    return r, g, b

def add_material(obj, material_name, h):  #=== material to cube 
    material = bpy.data.materials.get(material_name)
    if material is None:
        material = bpy.data.materials.new(material_name)
    material.use_nodes = True
    principled_bsdf = material.node_tree.nodes['Principled BSDF']
    if principled_bsdf is not None:
        principled_bsdf.inputs[0].default_value = (*hex_to_rgb(h), 1)  
    obj.active_material = material
# =================== definition , create apartment #FThick=1.5 meter (3 meter per floor ) (modified for blender4.1)
xy_bump = 1.05 #  building wide and narrow cube xy_bump ( 1 wide cube plus 1 narrow cube makes one floor)
def create_apartment(x_origin, y_origin, z_rot, NumOfStories, xScale, yScale, FThick, odd_color, even_color):
    for i in range (0, 2*NumOfStories, 2):
        bpy.ops.mesh.primitive_cube_add(size=1, enter_editmode=False, align='WORLD', location=(x_origin, y_origin, i * FThick), rotation=(0.0, 0.0, z_rot), scale=(xScale, yScale, FThick))
        obj = bpy.context.object
#        add_material( obj, "color01", odd_color )  
        add_material( obj, "", odd_color )  
        bpy.ops.mesh.primitive_cube_add(size=1, enter_editmode=False, align='WORLD', location=(x_origin, y_origin, FThick + i * FThick), rotation=(0.0, 0.0, z_rot), scale=(xScale*xy_bump, yScale*xy_bump, FThick))
        obj = bpy.context.object
#        add_material( obj, "color02", even_color ) 
        add_material( obj, "", even_color )    

# ======== create now z_rot:rotation,  NumOfStories:floors, 
# create_apartment(x_origin, y_origin, z_rot, NumOfStories, xScale, yScale, FThick, odd_color, even_color):
create_apartment(-21, -27, 1/180*3.14, 5, 15, 25, 1.5, 0x2F2F2F, 0xffe4b5) #ryowa #DARKSLATEGRAY#2F4F4F
create_apartment(-31, 4, -30/180*3.14, 15, 15, 18, 1.5, 0x2F2F2F, 0xffe4b5)  #HBF #DARKSLATEGRAY#2F4F4F
create_apartment(-25, 20, -30/180*3.14, 8, 18, 15, 1.5, 0xffe4b5, 0x222222) #apt5 bldg
create_apartment(-23, 40, 0/180*3.14, 2, 15, 30, 1.2, 0xeeeeee, 0x6495ed)  #boff #MAROON#800000 ,#DARKGRAY#A9A9A9  ##lightskyblue#87cefa #cornflowerblue#6495ed

create_apartment(-20, 68, 0/180*3.14, 4, 9, 9, 1.5, 0x2F2F2F, 0xffe4b5) #cosmos -20, 67, 10m 10m
create_apartment(14, 70, 0/180*3.14, 4, 22, 11, 1.5, 0x2F2F2F, 0xffe4b5) #seikei  x14,y70, 22m 11m
create_apartment(-50, 53, 0/180*3.14, 10, 10, 10, 1.5, 0x2F2F2F, 0xffe4b5) #lumiere_k1 -49,53,  scale 6,6
create_apartment(-60, 55, 0/180*3.14, 10, 12, 12, 1.5, 0x2F2F2F, 0xffe4b5) #lumiere_k2 -49,53,  scale 6,6
# ====== create kanbans ...  2 planes
bpy.ops.mesh.primitive_plane_add(size=4, enter_editmode=False, align='WORLD', location=(-15, 48, 6.25), rotation=(3.14/2, 0, 3.14/2), scale=(1,1,1))
bpy.context.active_object.name = 'kanban_book'
bpy.ops.mesh.primitive_plane_add(size=4, enter_editmode=False, align='WORLD', location=(-15, 13, 3.5), rotation=(3.14/2, 0, 3.14*0.4), scale=(1,1,1))
bpy.ops.transform.resize(value=(1, 3, 0.7)) 
bpy.context.active_object.name = 'kanban_higa'

#==================== beginning of STAIRS . skew rectangle
pi = math.pi
# URL https://tamaki-py.hatenablog.com/entry/2019/06/03/223545
#'''オブジェクトモードから始めなければなりません. scene が empty（空）であるときスクリプトは動きません.'''
## オブジェクトモードに変更.
#bpy.ops.object.mode_set(mode='OBJECT')
## 全てのオブジェクトを選択.
#bpy.ops.object.select_all(action='SELECT')
## 選択された全てのオブジェクトを削除.
#bpy.ops.object.delete()
#'''立方体を作成し, 編集モードに切り替え.'''
# 立方体を配置.
#######(-49,60, 0)
# === stairs east face
bpy.ops.mesh.primitive_cube_add(size=1, location=(-51, 61, 0)) ##lumiere_koi_bldg stairs
bpy.ops.transform.resize(value=(0.1, 4, 1.4))

# 編集モードに切り替え.
bpy.ops.object.mode_set(mode='EDIT')
# 全てのメッシュを非選択状態にする.
bpy.ops.mesh.select_all(action='DESELECT')
'''面モードにし, 一つの面を回転させる.'''
# 面モードに設定.
bpy.ops.mesh.select_mode(type="FACE")
# bmesh オブジェクトのインスタンス化.
b_mesh = bmesh.from_edit_mesh(bpy.context.object.data)
b_mesh.faces.ensure_lookup_table()
b_mesh.faces[3].select = True # ===  face number (3) south face 
bpy.ops.transform.translate(value=(0, 0, 3)) #=== move a face upward
bpy.ops.object.mode_set(mode='OBJECT')

for i in range(8):
    bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked":False, "mode":'TRANSLATION'}, TRANSFORM_OT_translate={"value":(0, 0, 3), "orient_type":'GLOBAL', "orient_matrix":((1, 0, 0), (0, 1, 0), (0, 0, 1)), "orient_matrix_type":'GLOBAL', "constraint_axis":(False, False, False), })
# === lumiere_koi_bldg stairs west face
bpy.ops.mesh.primitive_cube_add(size=1, location=(-53, 61, 0)) ##lumiere_koi_bldg stairs
bpy.ops.transform.resize(value=(0.1, 4, 1.4))

# 編集モードに切り替え.
bpy.ops.object.mode_set(mode='EDIT')
# 全てのメッシュを非選択状態にする.
bpy.ops.mesh.select_all(action='DESELECT')
'''面モードにし, 一つの面を回転させる.'''
# 面モードに設定.
bpy.ops.mesh.select_mode(type="FACE")
# bmesh オブジェクトのインスタンス化.
b_mesh = bmesh.from_edit_mesh(bpy.context.object.data)
b_mesh.faces.ensure_lookup_table()
b_mesh.faces[1].select = True # ===  face number (3) south face 
bpy.ops.transform.translate(value=(0, 0, 3)) #=== move a face upward
bpy.ops.object.mode_set(mode='OBJECT')
for i in range(8):
    bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked":False, "mode":'TRANSLATION'}, TRANSFORM_OT_translate={"value":(0, 0, 3), "orient_type":'GLOBAL', "orient_matrix":((1, 0, 0), (0, 1, 0), (0, 0, 1)), "orient_matrix_type":'GLOBAL', "constraint_axis":(False, False, False), })
# === lumiere_koi_bldg stairs north rectrangle face 
bpy.ops.mesh.primitive_cube_add(size=1, location=(-52, 63, 0)) ##lumiere_koi_bldg stairs
bpy.ops.transform.resize(value=(2,0.1,1.4)) #(0.1, 4, 1.4))
for i in range(8):
    bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked":False, "mode":'TRANSLATION'}, TRANSFORM_OT_translate={"value":(0, 0, 3), "orient_type":'GLOBAL', "orient_matrix":((1, 0, 0), (0, 1, 0), (0, 0, 1)), "orient_matrix_type":'GLOBAL', "constraint_axis":(False, False, False), })
#============================ end of STAIRS 

## === hodoukyo horizontal part
bpy.ops.mesh.primitive_cube_add(size=1, location=(-52, 67, 2.5))
bpy.ops.transform.resize(value=(2, 8, 1))
## === hodoukyo "v-shape" arch over the bridge
vlen = 12
vb_height =5 #apex height
ct_x = -52 # center x 
ct_y =  67 # center y
for i in range(-vlen, (vlen +1) ):  #（  (-3, 3)と書けばマイナス側3個原点に1個、プラス側2個　合計6個）
    x= i/2
    y= i/2
    z= vb_height - abs(i) / 8
    bpy.ops.mesh.primitive_cube_add(size=0.3, location=(ct_x + x*0.3, ct_y + y*0.3, z))
    bpy.ops.mesh.primitive_cube_add(size=0.3, location=(ct_x + x*0.3, ct_y -y*0.3, z))
    bpy.ops.mesh.primitive_cube_add(size=0.3, location=(ct_x + x*0.3, ct_y + -vlen*0.3/2, 3.5))
    bpy.ops.mesh.primitive_cube_add(size=0.3, location=(ct_x + x*0.3, ct_y + vlen*0.3/2, 3.5))
## === hodoukyo stairs part
bpy.ops.mesh.primitive_cube_add(size=1, location=(-49, 70, 1.3))
bpy.ops.transform.resize(value=(6, 2, 0.3))
# URL https://suzulang.com/blender-2-8-python-rotate/
# objに現在のアクティブなオブジェクトを指定する
obj = bpy.context.active_object

def rotate_object(rot_mat):
    # decompose world_matrix's components, and from them assemble 4x4 matrices
    orig_loc, orig_rot, orig_scale = obj.matrix_world.decompose()
    #
    orig_loc_mat   = Matrix.Translation(orig_loc)
    orig_rot_mat   = orig_rot.to_matrix().to_4x4()
    orig_scale_mat = (Matrix.Scale(orig_scale[0],4,(1,0,0)) @ 
                      Matrix.Scale(orig_scale[1],4,(0,1,0)) @ 
                      Matrix.Scale(orig_scale[2],4,(0,0,1)))
    #
    # assemble the new matrix
    obj.matrix_world = orig_loc_mat @ rot_mat @ orig_rot_mat @ orig_scale_mat 
# Matrix.Rotationで回転行列を作成
# Matrix.Rotation( ラジアンの回転角 , 4 , 回転軸 )
# 4 は4x4行列の意味
# 回転軸は(x,y,z)形式の他に 'X' や 'Y' や'Z' のように軸名を指定することもできる
rotate_object( Matrix.Rotation( radians(30), 4, (0,1,0) ) )


## === end of  hodoukyo

# =====  road
bpy.ops.mesh.primitive_plane_add(size=2, enter_editmode=False, align='WORLD', location=(-7, 90, 0), scale=(1, 1, 1))
bpy.ops.transform.resize(value=(3, 200, 1))
bpy.ops.mesh.primitive_plane_add(size=2, enter_editmode=False, align='WORLD', location=(-0.6, 120, 0), scale=(1, 1, 1), rotation=(0.0, 0.0, -6/180*3.14))
bpy.ops.transform.resize(value=(100, 1, 1))

# Add a plane for ground  ==================
bpy.ops.mesh.primitive_plane_add(size=400.0, align='WORLD', location=(0.0, 0.0, -0.5), rotation=(0.0, 0.0, 0.0) )
matp = bpy.data.materials.new('Plane')
matp.diffuse_color = (0.08, 0.08, 0.03, 0) 
obj = bpy.context.view_layer.objects.active
obj.data.materials.append(matp)

# ================== world - surface - background (背景) 
bpy.data.worlds["World"].node_tree.nodes["Background"].inputs[0].default_value = (0.01, 0.15, 0.25, 1)
bpy.data.worlds["World"].node_tree.nodes["Background"].inputs[1].default_value = 0.7      

# ============== "light"
# create light datablock, set attributes
#light_data = bpy.data.lights.new(name="light_spot1", type='SPOT')
light_data = bpy.data.lights.new(name="light_spot1", type='SUN')
light_data.energy = 5
# create new object with our light datablock
light_object1 = bpy.data.objects.new(name="light_spot1", object_data=light_data)
# link light object
bpy.context.collection.objects.link(light_object1)
# make it active 
bpy.context.view_layer.objects.active = light_object1
#change location
light_object1.location = (20, -10, 50)
light_object1.delta_rotation_euler = (1.3, 0, 0.3) #ゼロゼロゼロで真下を向く。
# update scene, if needed
dg = bpy.context.evaluated_depsgraph_get() 
dg.update()

light_data = bpy.data.lights.new(name="light_spot2", type='SPOT')
light_data.energy = 20000
# create new object with our light datablock
light_object2 = bpy.data.objects.new(name="light_spot2", object_data=light_data)
# link light object
bpy.context.collection.objects.link(light_object2)
# make it active 
bpy.context.view_layer.objects.active = light_object2
#change location
light_object2.location = (-20, 60, 40)
light_object2.delta_rotation_euler = (0.1, 0, 0.3) #ゼロゼロゼロで真下を向く。
# update scene, if needed
dg = bpy.context.evaluated_depsgraph_get() 
dg.update()

light_data = bpy.data.lights.new(name="light_spot3", type='SPOT')
light_data.energy = 20000
# create new object with our light datablock
light_object3 = bpy.data.objects.new(name="light_spot3", object_data=light_data)
# link light object
bpy.context.collection.objects.link(light_object3)
# make it active 
bpy.context.view_layer.objects.active = light_object3
#change location
light_object3.location = (-50, 60, 40)
light_object3.delta_rotation_euler = (0.1, 0, 0.3) #ゼロゼロゼロで真下を向く。
# update scene, if needed
dg = bpy.context.evaluated_depsgraph_get() 
dg.update()


# ================
#======= KOI HONMACHI Map ======
bpy.ops.object.load_reference_image(filepath="/Users/nh7/Dropbox/blenderF/bpykmapR2.jpg")
bpy.context.active_object.name = 'plane_map1'

bpy.context.object.scale[0] = 106
bpy.context.object.scale[1] = 106
bpy.context.object.location[0] = -58.6
bpy.context.object.location[1] = 70.7
#======= KOI HONMACHI Map ======END 


#======= car body manufacturing start
bpy.ops.mesh.primitive_cube_add(size=1, location=(0, 0, 0), scale=(1, 1, 1))
bpy.context.active_object.name = 'b_base'
bpy.ops.transform.resize(value=(1.5,3.4,0.9))
bpy.ops.mesh.primitive_plane_add(size=1, location=(0, -0.45, 0.4))
bpy.context.active_object.name = 'b_top'
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.inset(thickness=0.1, depth=0.6)
bpy.ops.object.editmode_toggle()
bpy.ops.transform.resize(value=(1.5,2.5,1))
bpy.data.objects['b_base'].select_set(True)
bpy.data.objects['b_top'].select_set(True)
for x in bpy.context.selected_objects: # same COLOR on tires and body
    objdd =  x.data
    mat = bpy.data.materials.new('Car_color')
    #h = 0xdc143c  ###0xdc143c= crimson
    h = 0x800000 #ox800000=maroon
    mat.diffuse_color = (*hex_to_rgb(h), 1) #======   COLOR
    objdd.materials.append(mat)
bpy.data.objects['b_base'].select_set(False)
bpy.data.objects['b_top'].select_set(False)

bpy.ops.mesh.primitive_cylinder_add(vertices=16, radius=0.3 , depth=1.6, end_fill_type='NGON', location=(0,1.0,-0.3) )
bpy.context.active_object.name = 'tire_fr'
bpy.ops.transform.rotate(value=90/180*3.14, orient_axis='Y' )
bpy.ops.mesh.primitive_cylinder_add(vertices=16, radius=0.3 , depth=1.6, end_fill_type='NGON', location=(0,-1.2,-0.3) )
bpy.context.active_object.name = 'tire_rr'
bpy.ops.transform.rotate(value=90/180*3.14, orient_axis='Y' )
bpy.data.objects['tire_fr'].select_set(True)
bpy.data.objects['tire_rr'].select_set(True)
for x in bpy.context.selected_objects: # same COLOR on tires and body
    objdd =  x.data
    mat = bpy.data.materials.new('Car_color') 
    h = 0x2f4f4f ###gray?????darkslategray
    mat.diffuse_color = (*hex_to_rgb(h), 1) #======   COLOR
    objdd.materials.append(mat)


bpy.data.objects['b_base'].select_set(True)
bpy.data.objects['b_top'].select_set(True)
bpy.data.objects['tire_fr'].select_set(True)
bpy.data.objects['tire_rr'].select_set(True)
bpy.ops.object.join()
bpy.context.active_object.name = 'joined_car1'
bpy.data.objects['joined_car1'].select_set(True)


#======= END of car body manufacturing 

# ================ CAR movement with KEY FRAME (2024.5.17)

bpy.context.scene.frame_start = 1
bpy.context.scene.frame_end = 60
bpy.context.scene.frame_current = 10

#== moveloc_xyz_list[frameNumber, x, y, z, z_ax_rot]
moveloc_xyz_list = [[1, -8,-9,1,0], [10,-8,15,1,0], [20,-8,53,1,-2], [22,-10,59,1,-30],
[25,-14,60,1,-30], [40,-30,64,1,-30],[50,-45,65,1,0],[60,-65,65,1,0]] 

bpy.data.objects['joined_car1'].select_set(True)
objects = bpy.data.objects

for i in range(len(moveloc_xyz_list)):
    frame_num=moveloc_xyz_list[i][0]
    xloc= moveloc_xyz_list[i][1]
    yloc= moveloc_xyz_list[i][2]
    zloc= moveloc_xyz_list[i][3]
    z_ax_rot=moveloc_xyz_list[i][4]
    bpy.context.scene.frame_set(frame_num) # set frame to frame_num
    objects['joined_car1'].location = (xloc, yloc, zloc)  # set location
    bpy.ops.transform.rotate(value=z_ax_rot/180*3.14, orient_axis='Z' )
    bpy.ops.anim.keyframe_insert_menu(type='Location') # KEY FRAME
    bpy.ops.anim.keyframe_insert_menu(type='Rotation')

bpy.ops.transform.rotate(value=0, orient_axis='Z' )
#==== end of CAR movement (2024.5.17)

# ================ make a new CURVE for camera movement
# ==== nunoheya BEGIN
curvedata = bpy.data.curves.new("my curve", type='CURVE')    
curvedata.dimensions = '3D'    

polyline = curvedata.splines.new('BEZIER')
polyline.bezier_points.add(2) # 制御点数ー１個

polyline.bezier_points[0].co = -1,-61,18
polyline.bezier_points[0].handle_left = -1,-74,18
polyline.bezier_points[0].handle_right = -6,-45,18

polyline.bezier_points[1].co = 0,30,18
polyline.bezier_points[1].handle_left = -3,15,18
polyline.bezier_points[1].handle_right = 0,43,18

polyline.bezier_points[2].co = -18,62,20
polyline.bezier_points[2].handle_left = 0,58,20
polyline.bezier_points[2].handle_right = -30,62,20

obj = bpy.data.objects.new("my bezier", curvedata) 
# 新しいCollectionを作成
newCol = bpy.data.collections.new('Collection 1')
# 現在のシーンにコレクションをリンク
bpy.context.scene.collection.children.link(newCol)
# コレクションにオブジェクトをリンク
newCol.objects.link(obj)
# ==== nunoheya END


#  ================== = camera movement
#bpy.ops.curve.primitive_bezier_circle_add(enter_editmode=False, align='WORLD', location=(20, 20, 30))
bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=(0,0,0))
bpy.ops.object.camera_add(enter_editmode=False, align='VIEW', location=(0,0,0), rotation=(0, 0, 0))

bpy.data.objects['Empty'].select_set(True)
bpy.data.objects['Camera'].select_set(True)

bpy.context.view_layer.objects.active = bpy.data.objects['Empty']
bpy.ops.object.parent_set(type='OBJECT')

bpy.data.objects['Camera'].select_set(False)
bpy.data.objects['Empty'].select_set(True)

bpy.ops.object.constraint_add(type='FOLLOW_PATH')
#bpy.context.object.constraints["Follow Path"].target = bpy.data.objects["BezierCircle"]
bpy.context.object.constraints["Follow Path"].target = bpy.data.objects["my bezier"]

bpy.context.object.constraints["Follow Path"].use_curve_follow = True
bpy.context.object.constraints["Follow Path"].use_fixed_location = True

bpy.data.objects['Empty'].select_set(False)
bpy.data.objects['Camera'].select_set(True)

bpy.ops.object.constraint_add(type='TRACK_TO')

#bpy.context.object.constraints["Track To"].target = bpy.data.objects["Cube.016"]
bpy.context.object.constraints["Track To"].target = bpy.data.objects["joined_car1"]
bpy.context.object.constraints["Track To"].up_axis = 'UP_Y'
bpy.context.object.constraints["Track To"].track_axis = 'TRACK_NEGATIVE_Z'  #5m00sec
#Camera Keyframe #(Insert keyframe to object's Offset Factor Python API - stack exchange)
bpy.data.objects['Camera'].select_set(False)
bpy.data.objects['Empty'].select_set(True)
bpy.context.scene.frame_current = 1
bpy.context.object.constraints["Follow Path"].offset_factor = 0
ob = bpy.context.object
# ob.constraints['Follow Path']
# bpy.data.objects['Empty'].constraints["Follow Path"]
# [bpy.data.objects['Empty'].constraints["Follow Path"]]
con = ob.constraints.get("Follow Path")
con.offset_factor = 0.0
con.keyframe_insert("offset_factor", frame=1)
con.offset_factor = 0.25
con.keyframe_insert("offset_factor", frame=12)
con.offset_factor = 0.50
con.keyframe_insert("offset_factor", frame=18)
con.offset_factor = 0.70
con.keyframe_insert("offset_factor", frame=30)
con.offset_factor = 0.80
con.keyframe_insert("offset_factor", frame=50)
con.offset_factor = 0.99
con.keyframe_insert("offset_factor", frame=60)

# ==== END of camera movement

# ======== to EDIT mode, then OBJECT mode ===

#「# 編集モードへの移行」2.8向けに2行ほど改良。

# 編集モードへの移行
# 引数   arg_objectname：指定オブジェクト名
# 戻り値
def set_mode_edit(arg_objectname='Default'):
  # 他のオブジェクトに操作を適用しないよう全てのオブジェクトを走査する
  for ob in bpy.context.scene.objects:
    # 非選択状態に設定する
    #ob.select=False  #blender2.7
    ob.select_set(False)
  # 指定オブジェクトを取得する
  selectob = bpy.data.objects[arg_objectname]
  # 変更オブジェクトをアクティブに変更する
  #bpy.context.scene.objects.active = selectob  #blender2.7
  bpy.context.view_layer.objects.active = selectob
  #
  # 編集モードに移行する
  bpy.ops.object.mode_set(mode='EDIT', toggle=False)
  return
# 関数の実行例
set_mode_edit('my bezier')
# =====
#「# オブジェクトモードへの移行」2.8向けに2行ほど改良。

# オブジェクトモードへの移行
# 引数   arg_objectname：指定オブジェクト名
# 戻り値
def set_mode_object(arg_objectname='Default'):
  # 他のオブジェクトに操作を適用しないよう全てのオブジェクトを走査する
    for ob in bpy.context.scene.objects:
    # 非選択状態に設定する
    #ob.select=False
        ob.select_set(False)
  # 指定オブジェクトを取得する
    selectob = bpy.data.objects[arg_objectname]
  # 変更オブジェクトをアクティブに変更する
  #bpy.context.scene.objects.active = selectob
    bpy.context.view_layer.objects.active = selectob
  # オブジェクトモードに移行する
    bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
    return
# 関数の実行例
set_mode_object('my bezier')
# ======== to EDIT mode, then OBJECT mode ===   END


```