Error in user YAML: (<unknown>): found a tab character that violate indentation while scanning a plain scalar at line 3 column 3
---
- oeasy Python 0739
- 这是 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`
---import bpy
import math
# 清除当前场景
bpy.ops.object.select_all(action="SELECT")
bpy.ops.object.delete()
def create_cow():
"""创建牛的模型"""
cow = bpy.data.objects.new("cow", None)
bpy.data.collections["Collection"].objects.link(cow)
# 创建牛的身体
bpy.ops.mesh.primitive_cube_add()
body_obj = bpy.context.object
body_obj.name = "cow_body"
body_obj.location = (0, 0, 2)
body_obj.scale = (3, 1.5, 1.2)
mat = bpy.data.materials.new('mat_cow_body')
mat.diffuse_color = (0.8, 0.7, 0.6, 1) # 浅棕色
body_obj.data.materials.append(mat)
body_obj.parent = cow
# 创建牛的头部
bpy.ops.mesh.primitive_cube_add()
head_obj = bpy.context.object
head_obj.name = "cow_head"
head_obj.location = (3.5, 0, 2.5)
head_obj.scale = (1.2, 1, 1)
mat = bpy.data.materials.new('mat_cow_head')
mat.diffuse_color = (0.9, 0.8, 0.7, 1) # 更浅的棕色
head_obj.data.materials.append(mat)
head_obj.parent = cow
# 创建牛的鼻子
bpy.ops.mesh.primitive_cube_add()
nose_obj = bpy.context.object
nose_obj.name = "cow_nose"
nose_obj.location = (1.2, 0, -0.3)
nose_obj.scale = (0.8, 0.6, 0.4)
mat = bpy.data.materials.new('mat_cow_nose')
mat.diffuse_color = (0.2, 0.1, 0.1, 1) # 深棕色
nose_obj.data.materials.append(mat)
nose_obj.parent = head_obj
# 创建牛的眼睛
bpy.ops.mesh.primitive_uv_sphere_add()
eye_l_obj = bpy.context.object
eye_l_obj.name = "cow_eye_l"
eye_l_obj.location = (0.8, 0.6, 0.4)
eye_l_obj.scale = (0.2, 0.2, 0.2)
mat = bpy.data.materials.new('mat_cow_eye_l')
mat.diffuse_color = (0, 0, 0, 1) # 黑色
eye_l_obj.data.materials.append(mat)
eye_l_obj.parent = head_obj
bpy.ops.mesh.primitive_uv_sphere_add()
eye_r_obj = bpy.context.object
eye_r_obj.name = "cow_eye_r"
eye_r_obj.location = (0.8, -0.6, 0.4)
eye_r_obj.scale = (0.2, 0.2, 0.2)
mat = bpy.data.materials.new('mat_cow_eye_r')
mat.diffuse_color = (0, 0, 0, 1) # 黑色
eye_r_obj.data.materials.append(mat)
eye_r_obj.parent = head_obj
# 创建牛的耳朵
bpy.ops.mesh.primitive_cube_add()
ear_l_obj = bpy.context.object
ear_l_obj.name = "cow_ear_l"
ear_l_obj.location = (-0.3, 0.8, 0.8)
ear_l_obj.scale = (0.3, 0.4, 0.6)
ear_l_obj.rotation_euler = (0, 0, 0.3)
mat = bpy.data.materials.new('mat_cow_ear_l')
mat.diffuse_color = (0.7, 0.6, 0.5, 1)
ear_l_obj.data.materials.append(mat)
ear_l_obj.parent = head_obj
bpy.ops.mesh.primitive_cube_add()
ear_r_obj = bpy.context.object
ear_r_obj.name = "cow_ear_r"
ear_r_obj.location = (-0.3, -0.8, 0.8)
ear_r_obj.scale = (0.3, 0.4, 0.6)
ear_r_obj.rotation_euler = (0, 0, -0.3)
mat = bpy.data.materials.new('mat_cow_ear_r')
mat.diffuse_color = (0.7, 0.6, 0.5, 1)
ear_r_obj.data.materials.append(mat)
ear_r_obj.parent = head_obj
# 创建牛的四条腿
leg_positions = [(-1.5, 0.8, 0), (-1.5, -0.8, 0), (1.5, 0.8, 0), (1.5, -0.8, 0)]
for i, pos in enumerate(leg_positions):
bpy.ops.mesh.primitive_cylinder_add()
leg_obj = bpy.context.object
leg_obj.name = f"cow_leg_{i+1}"
leg_obj.location = pos
leg_obj.scale = (0.3, 0.3, 1)
mat = bpy.data.materials.new(f'mat_cow_leg_{i+1}')
mat.diffuse_color = (0.6, 0.5, 0.4, 1)
leg_obj.data.materials.append(mat)
leg_obj.parent = cow
# 创建牛的尾巴
bpy.ops.mesh.primitive_cylinder_add()
tail_obj = bpy.context.object
tail_obj.name = "cow_tail"
tail_obj.location = (-3.5, 0, 2.5)
tail_obj.scale = (0.1, 0.1, 1.5)
tail_obj.rotation_euler = (0.5, 0, 0)
mat = bpy.data.materials.new('mat_cow_tail')
mat.diffuse_color = (0.4, 0.3, 0.2, 1)
tail_obj.data.materials.append(mat)
tail_obj.parent = cow
return cow, head_obj
def create_grass_field():
"""创建草地和草丛"""
# 创建草地
bpy.ops.mesh.primitive_plane_add(size=20)
ground_obj = bpy.context.object
ground_obj.name = "grass_ground"
ground_obj.location = (0, 0, 0)
mat = bpy.data.materials.new('mat_grass_ground')
mat.diffuse_color = (0.2, 0.6, 0.1, 1) # 草绿色
ground_obj.data.materials.append(mat)
# 创建草丛
grass_positions = [
(4, 2, 0.1), (3.5, 1.5, 0.1), (4.2, 1.8, 0.1),
(5, 1, 0.1), (4.8, 0.5, 0.1), (5.2, 1.3, 0.1),
(3.8, 0.8, 0.1), (4.5, 0.2, 0.1), (5.5, 0.8, 0.1)
]
for i, pos in enumerate(grass_positions):
bpy.ops.mesh.primitive_cylinder_add()
grass_obj = bpy.context.object
grass_obj.name = f"grass_{i+1}"
grass_obj.location = pos
grass_obj.scale = (0.05, 0.05, 0.3)
mat = bpy.data.materials.new(f'mat_grass_{i+1}')
mat.diffuse_color = (0.1, 0.8, 0.2, 1) # 鲜绿色
grass_obj.data.materials.append(mat)
def create_camera():
"""创建摄像头"""
bpy.ops.object.camera_add()
camera = bpy.context.object
camera.name = "main_camera"
camera.location = (12, -8, 6)
camera.rotation_euler = (1.2, 0, 0.8)
bpy.context.scene.camera = camera
return camera
def create_lights():
"""创建光照"""
# 主光源
bpy.ops.object.light_add(type='SUN')
sun_light = bpy.context.object
sun_light.name = "sun_light"
sun_light.location = (8, -5, 10)
sun_light.rotation_euler = (0.5, 0, 0.3)
sun_light.data.energy = 5
# 补光
bpy.ops.object.light_add(type='SPOT')
spot_light = bpy.context.object
spot_light.name = "spot_light"
spot_light.location = (2, 5, 8)
spot_light.rotation_euler = (1.1, 0, -0.5)
spot_light.data.energy = 3000
def animate_cow_eating(cow_obj, head_obj):
"""创建牛吃草的动画"""
# 设置动画帧数 (10秒 * 24fps = 240帧)
bpy.context.scene.frame_start = 1
bpy.context.scene.frame_end = 240
# 创建吃草动画循环
eating_cycle_frames = 40 # 每个吃草循环40帧
num_cycles = 6 # 6个循环
for cycle in range(num_cycles):
start_frame = cycle * eating_cycle_frames + 1
# 头部初始位置
head_obj.location = (3.5, 0, 2.5)
head_obj.rotation_euler = (0, 0, 0)
head_obj.keyframe_insert(data_path="location", frame=start_frame)
head_obj.keyframe_insert(data_path="rotation_euler", frame=start_frame)
# 头部低下吃草
head_obj.location = (4.5, 0, 0.5)
head_obj.rotation_euler = (0.8, 0, 0)
head_obj.keyframe_insert(data_path="location", frame=start_frame + 15)
head_obj.keyframe_insert(data_path="rotation_euler", frame=start_frame + 15)
# 咀嚼动作(小幅度左右摆动)
head_obj.location = (4.3, 0.2, 0.3)
head_obj.keyframe_insert(data_path="location", frame=start_frame + 20)
head_obj.location = (4.7, -0.2, 0.4)
head_obj.keyframe_insert(data_path="location", frame=start_frame + 25)
head_obj.location = (4.5, 0, 0.5)
head_obj.keyframe_insert(data_path="location", frame=start_frame + 30)
# 抬头
head_obj.location = (3.5, 0, 2.5)
head_obj.rotation_euler = (0, 0, 0)
head_obj.keyframe_insert(data_path="location", frame=start_frame + 40)
head_obj.keyframe_insert(data_path="rotation_euler", frame=start_frame + 40)
# 添加身体的轻微移动
for cycle in range(num_cycles):
start_frame = cycle * eating_cycle_frames + 1
# 身体轻微前倾
cow_obj.location = (0, 0, 0)
cow_obj.rotation_euler = (0, 0, 0)
cow_obj.keyframe_insert(data_path="location", frame=start_frame)
cow_obj.keyframe_insert(data_path="rotation_euler", frame=start_frame)
cow_obj.location = (0.5, 0, 0)
cow_obj.rotation_euler = (0, 0.1, 0)
cow_obj.keyframe_insert(data_path="location", frame=start_frame + 15)
cow_obj.keyframe_insert(data_path="rotation_euler", frame=start_frame + 15)
cow_obj.location = (0, 0, 0)
cow_obj.rotation_euler = (0, 0, 0)
cow_obj.keyframe_insert(data_path="location", frame=start_frame + 40)
cow_obj.keyframe_insert(data_path="rotation_euler", frame=start_frame + 40)
def animate_camera(camera_obj):
"""创建摄像头运动"""
# 摄像头缓慢环绕牛
bpy.context.scene.frame_start = 1
bpy.context.scene.frame_end = 240
# 关键帧位置
camera_positions = [
(12, -8, 6, 1.2, 0, 0.8), # 起始位置
(8, -12, 7, 1.1, 0, 0.5), # 右侧
(0, -10, 8, 1.0, 0, 0), # 正面
(-8, -6, 6, 1.2, 0, -0.5), # 左侧
(12, -8, 6, 1.2, 0, 0.8) # 回到起始位置
]
frames = [1, 60, 120, 180, 240]
for i, (frame, (x, y, z, rx, ry, rz)) in enumerate(zip(frames, camera_positions)):
camera_obj.location = (x, y, z)
camera_obj.rotation_euler = (rx, ry, rz)
camera_obj.keyframe_insert(data_path="location", frame=frame)
camera_obj.keyframe_insert(data_path="rotation_euler", frame=frame)
def setup_render():
"""设置渲染参数"""
bpy.context.scene.render.engine = 'CYCLES'
bpy.context.scene.render.resolution_x = 1920
bpy.context.scene.render.resolution_y = 1080
bpy.context.scene.render.resolution_percentage = 50
bpy.context.scene.render.fps = 24
bpy.context.scene.render.filepath = '/tmp/cow_eating_grass'
def render_animation():
"""渲染动画"""
bpy.ops.render.render(animation=True)
def main():
"""主函数"""
# 创建模型
cow, head = create_cow()
create_grass_field()
camera = create_camera()
create_lights()
# 创建动画
animate_cow_eating(cow, head)
animate_camera(camera)
# 设置渲染
setup_render()
# 渲染动画
#render_animation()
if __name__ == "__main__":
main()
- 本文来自 oeasy Python 系统教程。
- 想完整、扎实学 Python,
- 搜索 oeasy 即可。
