Blender中Python for循环内location值不更新,添加的Armature全部位于首个对象
问题核心排查
首先排除你的初步猜测:循环中的
loc变量实际会随迭代正常更新,变量赋值不存在失效问题。
真正的故障原因有两个:
bpy.ops.object.armature_add属于依赖上下文的操作:它的生成位置不会完全以传入的location参数为准,会优先锚定当前场景3D光标的位置,参数传入的坐标在上下文不匹配时会被游标值覆盖。循环启动后第一次操作会把光标固定在第一组坐标对应的位置,后续所有生成的Armature都会沿用这个固定光标位置,最终出现所有骨骼都堆在第一个对象旁的现象。- 循环内用数字索引直接取
bpy.data.objects[count]的写法存在固有隐患:Blender的对象集合索引顺序会随场景内对象删除、排序、导入动态变化,很容易取错目标对象,这也是后续调试需要额外注意的问题。
可落地修复方案
方案1:绕开bpy.ops上下文限制,直接调用底层数据API
这是批量生成场景对象最稳定、最快的写法,完全不依赖3D光标、激活对象等上下文状态,不会出现位置错位:
import bpy # 提前筛选所有需要绑定骨骼的网格对象,不要靠硬索引取值 target_meshes = [obj for obj in bpy.context.scene.objects if obj.type == 'MESH'] for target in target_meshes: # 创建Armature数据块 arm_data = bpy.data.armatures.new(name=f"{target.name}_Bone") # 创建对应Armature对象实例 arm_instance = bpy.data.objects.new(name=f"{target.name}_Bone", object_data=arm_data) # 把对象挂载到场景集合中,未挂载的对象不会在视口显示 bpy.context.scene.collection.objects.link(arm_instance) # 直接设置对象坐标,完全不受外部状态干扰 arm_instance.location = (target.location.x, target.location.y, target.location.z + 0.1) # 可选:直接建立父子绑定,省去后续手动设置父级的步骤 target.parent = arm_instance
方案2:保留原有bpy.ops写法的修复方式
如果不想改动原有操作逻辑,必须在每次循环迭代时手动同步3D光标的位置,抵消上下文对生成位置的影响:
for count in range(1, value, 1): target_obj = bpy.data.objects[count] # 手动将3D光标对齐到当前迭代对象的坐标位置 bpy.context.scene.cursor.location = ( target_obj.location.x, target_obj.location.y, target_obj.location.z + 0.1 ) # 保证激活对象为当前迭代目标,满足操作的上下文要求 bpy.context.view_layer.objects.active = target_obj bpy.ops.object.armature_add( enter_editmode=False, align='WORLD', location=(0, 0, 0), # 此时位置由光标决定,传相对原点值即可 scale=(1, 1, 1) )
额外调试注意点
- 批量操作时尽量不要用数字索引遍历场景对象,优先按对象类型、自定义属性、固定名称做筛选匹配,避免场景对象变动导致取错目标
- 直接调用底层数据API的执行效率比bpy.ops高一个数量级,批量生成几十个Armature时不会出现界面卡顿、操作排队的问题
内容的提问来源于stack exchange,提问作者Tentanus
相关产品推荐
相关产品推荐

