Skip to content

Latest commit

 

History

History
307 lines (263 loc) · 10.3 KB

File metadata and controls

307 lines (263 loc) · 10.3 KB
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 即可。