计算机图形学--实时物理模拟的柔体动画(Python)

实时物理模拟的柔体动画:利用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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值