
实时物理模拟的柔体动画:利用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()
Python实现实时物理模拟柔体动画
535

被折叠的 条评论
为什么被折叠?



