实时物理模拟的柔体动画:利用Python和相关库(如PyBullet或自制物理引擎)实现柔体(如布料、绳索)的实时动画模拟。需要考虑柔体的弹性、阻尼、重力等物理属性,通过有限元方法或弹簧 - 质点模型来模拟柔体的变形,并且将模拟结果实时渲染成动画展示。
import pygame import math # 初始化 Pygame pygame.init() # 设置窗口尺寸 width, height = 1000, 600 screen = pygame.display.set_mode((width, height)) pygame.display.set_caption("Cloth Simulation") # 定义颜色 WHITE = (255, 255, 255) SKY_BLUE = (0, 191, 255) BLACK = (0, 0, 0) GRAY = (128, 128, 128) LIGHT_GRAY = (200, 200, 200) # 布料参数 cloth_width = 30 # 进一步增加布料的宽度分辨率 cloth_height = 30 # 进一步增加布料的高度分辨率 particle_mass = 1.0 spring_stiffness = 3.0 # 进一步降低弹簧刚度,避免质点运动过快 damping = 0.25 # 适当增加阻尼,稳定布料运动 gravity = 0.0005 # 进一步降低重力,使布料运动更平缓 # 初始化布料质点 particles = [] for i in range(cloth_width): for j in range(cloth_height): x = i * 10 + 200 # 减小质点间距 y = j * 10 + 100 # 减小质点间距 particles.append([x, y, 0, 0]) # [x, y, vx, vy] # 定义弹簧连接 springs = [] for i in range(cloth_width): for j in range(cloth_height): if i < cloth_width - 1: springs.append((i * cloth_height + j, (i + 1) * cloth_height + j)) if j < cloth_height - 1: springs.append((i * cloth_height + j, i * cloth_height + j + 1)) # 控制参数 enable_gravity = True enable_spring = True enable_damping = True simulation_speed = 0.1 # 进一步降低初始模拟速度 # 复选框参数 checkbox_size = 20 checkbox_x = width - 200 checkbox_y = 50 checkbox_spacing = 30 # 滑动条参数 slider_x = width - 200 slider_y = checkbox_y + 4 * checkbox_spacing slider_width = 150 slider_height = 10 slider_handle_radius = 10 slider_min_value = 0.05 slider_max_value = 1.0 # 调整滑动条的最大值,使其更符合实际需求 # 字体设置 font = pygame.font.Font(None, 36) # 记录鼠标按下时是否在滑动条上 slider_dragging = False # 主循环 running = True clock = pygame.time.Clock() while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.MOUSEBUTTONDOWN: mouse_x, mouse_y = event.pos # 检查是否点击了重力复选框 gravity_checkbox_rect = pygame.Rect(checkbox_x, checkbox_y, checkbox_size, checkbox_size) if gravity_checkbox_rect.collidepoint(mouse_x, mouse_y): enable_gravity = not enable_gravity # 检查是否点击了弹簧弹性复选框 spring_checkbox_rect = pygame.Rect(checkbox_x, checkbox_y + checkbox_spacing, checkbox_size, checkbox_size) if spring_checkbox_rect.collidepoint(mouse_x, mouse_y): enable_spring = not enable_spring # 检查是否点击了阻尼复选框 damping_checkbox_rect = pygame.Rect(checkbox_x, checkbox_y + 2 * checkbox_spacing, checkbox_size, checkbox_size) if damping_checkbox_rect.collidepoint(mouse_x, mouse_y): enable_damping = not enable_damping # 检查是否点击了滑动条 slider_rect = pygame.Rect(slider_x, slider_y, slider_width, slider_height) if slider_rect.collidepoint(mouse_x, mouse_y): slider_dragging = True elif event.type == pygame.MOUSEBUTTONUP: slider_dragging = False elif event.type == pygame.MOUSEMOTION: if slider_dragging: mouse_x, _ = event.pos handle_x = max(slider_x, min(mouse_x, slider_x + slider_width)) simulation_speed = ((handle_x - slider_x) / slider_width) * ( slider_max_value - slider_min_value) + slider_min_value # 应用重力 if enable_gravity: for particle in particles: particle[3] += gravity * simulation_speed # 应用弹簧力 if enable_spring: for spring in springs: p1_index, p2_index = spring p1 = particles[p1_index] p2 = particles[p2_index] dx = p2[0] - p1[0] dy = p2[1] - p1[1] distance = math.sqrt(dx * dx + dy * dy) rest_length = 10 # 调整弹簧的静止长度 force = spring_stiffness * (distance - rest_length) force_x = force * (dx / distance) force_y = force * (dy / distance) p1[2] += force_x / particle_mass * simulation_speed p1[3] += force_y / particle_mass * simulation_speed p2[2] -= force_x / particle_mass * simulation_speed p2[3] -= force_y / particle_mass * simulation_speed # 应用阻尼 if enable_damping: for particle in particles: particle[2] *= (1 - damping) particle[3] *= (1 - damping) # 更新位置 for particle in particles: particle[0] += particle[2] * simulation_speed particle[1] += particle[3] * simulation_speed # 绘制背景 screen.fill(WHITE) # 绘制弹簧 for spring in springs: p1_index, p2_index = spring p1 = particles[p1_index] p2 = particles[p2_index] pygame.draw.line(screen, BLACK, (p1[0], p1[1]), (p2[0], p2[1]), 1) # 绘制质点 for particle in particles: pygame.draw.circle(screen, SKY_BLUE, (int(particle[0]), int(particle[1])), 2) # 进一步减小质点的半径 # 绘制复选框和标签 pygame.draw.rect(screen, GRAY if enable_gravity else WHITE, (checkbox_x, checkbox_y, checkbox_size, checkbox_size), 2) if enable_gravity: pygame.draw.line(screen, GRAY, (checkbox_x, checkbox_y), (checkbox_x + checkbox_size, checkbox_y + checkbox_size), 2) pygame.draw.line(screen, GRAY, (checkbox_x, checkbox_y + checkbox_size), (checkbox_x + checkbox_size, checkbox_y), 2) text = font.render("Gravity", True, BLACK) screen.blit(text, (checkbox_x + checkbox_size + 10, checkbox_y)) pygame.draw.rect(screen, GRAY if enable_spring else WHITE, (checkbox_x, checkbox_y + checkbox_spacing, checkbox_size, checkbox_size), 2) if enable_spring: pygame.draw.line(screen, GRAY, (checkbox_x, checkbox_y + checkbox_spacing), (checkbox_x + checkbox_size, checkbox_y + checkbox_spacing + checkbox_size), 2) pygame.draw.line(screen, GRAY, (checkbox_x, checkbox_y + checkbox_spacing + checkbox_size), (checkbox_x + checkbox_size, checkbox_y + checkbox_spacing), 2) text = font.render("Spring", True, BLACK) screen.blit(text, (checkbox_x + checkbox_size + 10, checkbox_y + checkbox_spacing)) pygame.draw.rect(screen, GRAY if enable_damping else WHITE, (checkbox_x, checkbox_y + 2 * checkbox_spacing, checkbox_size, checkbox_size), 2) if enable_damping: pygame.draw.line(screen, GRAY, (checkbox_x, checkbox_y + 2 * checkbox_spacing), (checkbox_x + checkbox_size, checkbox_y + 2 * checkbox_spacing + checkbox_size), 2) pygame.draw.line(screen, GRAY, (checkbox_x, checkbox_y + 2 * checkbox_spacing + checkbox_size), (checkbox_x + checkbox_size, checkbox_y + 2 * checkbox_spacing), 2) text = font.render("Damping", True, BLACK) screen.blit(text, (checkbox_x + checkbox_size + 10, checkbox_y + 2 * checkbox_spacing)) # 绘制滑动条 pygame.draw.rect(screen, LIGHT_GRAY, (slider_x, slider_y, slider_width, slider_height)) handle_x = slider_x + ((simulation_speed - slider_min_value) / (slider_max_value - slider_min_value)) * slider_width pygame.draw.circle(screen, GRAY, (int(handle_x), slider_y + slider_height // 2), slider_handle_radius) text = font.render(f"Speed: {simulation_speed:.2f}", True, BLACK) screen.blit(text, (slider_x, slider_y - 30)) # 更新显示 pygame.display.flip() clock.tick(30) # 退出 Pygame pygame.quit()