Error in user YAML: (<unknown>): found a tab character that violate indentation while scanning a plain scalar at line 3 column 3
---
- oeasy Python 0742
- 这是 oeasy 系统化 Python 教程,从基础一步步讲,扎实、完整、不跳步。愿意花时间学,就能真正学会。
- 本教程同步发布在:
- 个人网站: `https://oeasy.org`
- 蓝桥云课: `https://www.lanqiao.cn/courses/3584`
- GitHub: `https://github.com/overmind1980/oeasy-python-tutorial`
- Gitee: `https://gitee.com/overmind1980/oeasypython`
---- 先添加一个立方体
- 按下shift先后点选两个立方体
- 添加父子关系
- Object - Parent - Object
- 在两个立方体之间建立父子关系之后
- 两者之间会有一条连线
- 旋转父级对象
- 子级对象 会跟随
- 父亲 带着 儿子
- 移动、旋转、缩放
- 代码应该如何完成
import bpy
# 清空当前场景(先删旧对象)
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
# 创建两个立方体
bpy.ops.mesh.primitive_cube_add(size=1.0)
father = bpy.context.active_object
father.name = 'father'
bpy.ops.mesh.primitive_cube_add(size=1.0)
child = bpy.context.active_object
child.name = 'child'
child.location = (2, 2, 0)
# 先后选中 并设置父子关系
father.select_set(True)
armature.select_set(True)
bpy.ops.object.parent_set()
- 选中子对象
- Object - Parent - Clear Parent
- 清除父级关系
- 然后两者之间
- 连线消失
- 父子关系消失
- 子只能有一个父亲
- 父亲 可以有多个子
- 选中对象
- 右键
- 一拖二
- 控制旋转
- 甚至可以 一拖三
import bpy
# 清除场景中已有的物体
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
# 创建父立方体
bpy.ops.mesh.primitive_cube_add(size=1.5, enter_editmode=False, location=(0, 1, 1))
parent_cube = bpy.context.active_object
# 创建第一个子立方体
bpy.ops.mesh.primitive_cube_add(size=1, enter_editmode=False, location=(2, 2, 0))
child_cube1 = bpy.context.active_object
child_cube1.parent = parent_cube
# 创建第二个子立方体
bpy.ops.mesh.primitive_cube_add(size=1, enter_editmode=False, location=(-2, 2, 0))
child_cube2 = bpy.context.active_object
child_cube2.parent = parent_cube
# 创建第三个子立方体
bpy.ops.mesh.primitive_cube_add(size=1, enter_editmode=False, location=(0, 2, 0))
child_cube3 = bpy.context.active_object
child_cube3.parent = parent_cube
- 通过 对象之间的 父子关系
- 实现了层级控制
- 可以利用骨骼来控制这些对象吗?
import bpy
# 清除场景中已有的物体
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
- 清场景
- 建立骨架 Armature
- 场景中 出现了一个Bone
- 骨架 里面 只有一根 骨骼
- 骨骼看起来像 飞镖
- 切换到layout布局
- 切换到四视图
- 选中骨骼
- 设置 编辑模式
- 选中挤出工具e
- 挤出子骨骼
- 修改骨骼名称
- 父级 为 upper_arm 大臂
- 子级 为 forearm 小臂
- 可以用代码生成骨架吗?
import bpy
# 删除所有对象
for obj in bpy.data.objects:
bpy.data.objects.remove(obj)
for armature in bpy.data.armatures:
bpy.data.armatures.remove(armature)
# 创建一个新的Armature数据块
arm_data = bpy.data.armatures.new("arm_data")
# 创建一个新的对象并关联到上述Armature数据块
arm_obj = bpy.data.objects.new("arm_obj", arm_data)
# 确保 Armature 对象被链接到指定的集合
collection = bpy.data.collections.get("Collection")
collection.objects.link(arm_obj)
# 进入编辑模式
bpy.context.view_layer.objects.active = arm_obj
bpy.ops.object.mode_set(mode='EDIT')
# 获取编辑模式下的骨骼数据
edit_bones = arm_data.edit_bones
# 创建骨骼
upper_arm = edit_bones.new("upper_arm")
upper_arm.head = (0, 0, -1)
upper_arm.tail = (0, 0, 0)
# 创建子骨骼
forearm = edit_bones.new("forearm")
forearm.head = upper_arm.tail
forearm.tail = (0, 0, 1)
# 设置子骨骼的父骨骼为parent_bone
forearm.parent = upper_arm
# 退出编辑模式
bpy.ops.object.mode_set(mode='OBJECT')
- 效果
- 如何才能选中骨骼呢?
- 进入姿势(pose)模式
- 选中大臂(upper_arm)
- 旋转
- 观察到 大臂
- 在 骨骼属性中 旋转值 修改
- 并 带动 小臂
- 在大臂旋转的基础上
- 旋转小臂
- 修改 骨骼旋转值
import bpy
# 删除所有对象
for obj in bpy.data.objects:
bpy.data.objects.remove(obj)
for armature in bpy.data.armatures:
bpy.data.armatures.remove(armature)
# 创建一个新的Armature数据块
arm_data = bpy.data.armatures.new("arm_data")
# 创建一个新的对象并关联到上述Armature数据块
arm_obj = bpy.data.objects.new("arm_obj", arm_data)
# 确保 Armature 对象被链接到指定的集合
collection = bpy.data.collections.get("Collection")
collection.objects.link(arm_obj)
# 进入编辑模式
bpy.context.view_layer.objects.active = arm_obj
bpy.ops.object.mode_set(mode='EDIT')
# 获取编辑模式下的骨骼数据
edit_bones = arm_data.edit_bones
# 创建骨骼
upper_arm = edit_bones.new("upper_arm")
upper_arm.head = (0, 0, -1)
upper_arm.tail = (0, 0, 0)
# 创建子骨骼
forearm = edit_bones.new("forearm")
forearm.head = upper_arm.tail
forearm.tail = (0, 0, 1)
# 设置子骨骼的父骨骼为parent_bone
forearm.parent = upper_arm
# 退出编辑模式
bpy.ops.object.mode_set(mode='OBJECT')
- 新建 圆柱体
- 并设置属性
- 修改名字 为 upper_arm_obj
- 复制 此圆柱对象
- 向下移动位置
- 改名为
- 小臂对象
- forearm_obj
- 目前看不到骨架
- 选中骨架
- 视窗 可视化
- 名字
- 在最前
- 视窗 可视化
- 观察视窗变化
import bpy
# 删除所有对象
for obj in bpy.data.objects:
bpy.data.objects.remove(obj)
for armature in bpy.data.armatures:
bpy.data.armatures.remove(armature)
# 创建一个新的Armature数据块
arm_data = bpy.data.armatures.new("arm_data")
# 创建一个新的对象并关联到上述Armature数据块
arm_obj = bpy.data.objects.new("arm_obj", arm_data)
# 确保 Armature 对象被链接到指定的集合
collection = bpy.data.collections.get("Collection")
collection.objects.link(arm_obj)
# 进入编辑模式
bpy.context.view_layer.objects.active = arm_obj
bpy.ops.object.mode_set(mode='EDIT')
# 获取编辑模式下的骨骼数据
edit_bones = arm_data.edit_bones
# 创建骨骼
upper_arm = edit_bones.new("upper_arm")
upper_arm.head = (0, 0, -1)
upper_arm.tail = (0, 0, 0)
# 创建子骨骼
forearm = edit_bones.new("forearm")
forearm.head = upper_arm.tail
forearm.tail = (0, 0, 1)
# 设置子骨骼的父骨骼为parent_bone
forearm.parent = upper_arm
# 退出编辑模式
bpy.ops.object.mode_set(mode='OBJECT')
# 创建小臂圆柱体
bpy.ops.mesh.primitive_cylinder_add(
radius=0.3, # 圆柱体半径
depth=1, # 圆柱体高度
)
forearm_obj = bpy.context.active_object
forearm_obj.name = "forearm_obj"
forearm_obj.location = (0, 0, 0.5)
# 创建大臂圆柱体
bpy.ops.mesh.primitive_cylinder_add(
radius=0.3, # 圆柱体半径
depth=1, # 圆柱体高度
)
upper_arm_obj = bpy.context.active_object
upper_arm_obj.name = "upper_arm_obj"
# 将大臂圆柱体的位置和旋转设置为默认值
upper_arm_obj.location = (0, 0, -0.5)
- 选中 骨架 进入姿态模式
- 先选中 骨架中的小臂骨骼 准备作为 父亲
- 再ctrl选中 Mesh中的 小臂 准备作为 儿子
- 小臂mesh 进入 骨架(armature) 对象
- 选择 姿势(Pose)模式
- 旋转 小臂骨骼
- 会影响到 小臂网格(Mesh)对象
- 将 小臂骨骼 回正
- 姿势(Pose)模式下
- 先选中 大臂骨骼
- 然后 选择 大臂 网格(Mesh) 对象
- 对象模式下
- 设置 对象 - 父级 - 骨骼
- 将 大臂 放入骨骼
- 姿势 模式下
- 旋转 大臂 骨骼
- 大臂 网格 对象 跟着旋转
- 小臂 骨骼 跟着 大臂 旋转
- 小臂 网格 跟着 小臂 骨骼 旋转
- 旋转 大臂 骨骼
- 旋转 小臂 骨骼
- 小臂 网格 跟着 小臂 骨骼旋转
- 可以把这一切代码化吗?
- 在原代码基础上 更进一步
- 可以实现需求
# 删除所有对象
for obj in bpy.data.objects:
bpy.data.objects.remove(obj)
for armature in bpy.data.armatures:
bpy.data.armatures.remove(armature)
# 创建一个新的Armature数据块
arm_data = bpy.data.armatures.new("arm_data")
# 创建一个新的对象并关联到上述Armature数据块
arm_obj = bpy.data.objects.new("arm_obj", arm_data)
# 确保 Armature 对象被链接到指定的集合
collection = bpy.data.collections.get("Collection")
collection.objects.link(arm_obj)
# 设置骨骼显示在最前方,方便观察和操作
arm_obj.show_in_front = True
# 进入编辑模式
bpy.context.view_layer.objects.active = arm_obj
bpy.ops.object.mode_set(mode='EDIT')
# 获取编辑模式下的骨骼数据
edit_bones = arm_data.edit_bones
# 创建骨骼
upper_arm = edit_bones.new("upper_arm")
upper_arm.head = (0, 0, -1)
upper_arm.tail = (0, 0, 0)
# 创建子骨骼
forearm = edit_bones.new("forearm")
forearm.head = upper_arm.tail
forearm.tail = (0, 0, 1)
# 设置子骨骼的父骨骼为parent_bone
forearm.parent = upper_arm
# 退出编辑模式
bpy.ops.object.mode_set(mode='OBJECT')
# 创建小臂圆柱体
bpy.ops.mesh.primitive_cylinder_add(
radius=0.3, # 圆柱体半径
depth=1, # 圆柱体高度
)
forearm_obj = bpy.context.active_object
forearm_obj.name = "forearm_obj"
forearm_obj.location = (0, 0, 0.5)
# 创建大臂圆柱体
bpy.ops.mesh.primitive_cylinder_add(
radius=0.3, # 圆柱体半径
depth=1, # 圆柱体高度
)
upper_arm_obj = bpy.context.active_object
upper_arm_obj.name = "upper_arm_obj"
# 将大臂圆柱体的位置和旋转设置为默认值
upper_arm_obj.location = (0, 0, -0.5)
# 绑定函数:使用 parent_set operator 确保 keep_transform 生效
def parent_object_to_bone(obj, armature, bone_name):
# 确保在 Object Mode 下进行选择
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.select_all(action='DESELECT')
# 选中子物体和骨架
obj.select_set(True)
armature.select_set(True)
# 激活骨架
bpy.context.view_layer.objects.active = armature
# 进入 Pose Mode
bpy.ops.object.mode_set(mode='POSE')
# 使用 operator 取消所有骨骼的选择 (兼容性更好)
bpy.ops.pose.select_all(action='DESELECT')
# 激活目标骨骼
armature.data.bones.active = armature.data.bones[bone_name]
# 选中目标骨骼 (兼容不同版本 API)
# Blender 4.0+ 使用 PoseBone.select,旧版本使用 PoseBone.bone.select
pbone = armature.pose.bones[bone_name]
try:
pbone.bone.select = True
except AttributeError:
pbone.select = True
# 执行绑定,保持变换
bpy.ops.object.parent_set(type='BONE', keep_transform=True)
# 回到 Object Mode
bpy.ops.object.mode_set(mode='OBJECT')
# 绑定大臂
parent_object_to_bone(upper_arm_obj, arm_obj, "upper_arm")
# 绑定小臂
parent_object_to_bone(forearm_obj, arm_obj, "forearm")
-
这次 通过骨骼 控制对象了
- 骨骼 就是 父子关系
- 把对象挂接到骨头上 就可以控制对象了
-
但是 这是 将对象作为一个整体 控制呢?
- 如何控制具体的点呢?
- 本文来自 oeasy Python 系统教程。
- 想完整、扎实学 Python,
- 搜索 oeasy 即可。
































