You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pygame中3D曲线动画异常:仅显示局部且无法旋转

问题修复方案

核心错误分析

  • 仅显示曲线局部:draw_3d_lines函数在循环内部提前return,导致只绘制了曲线的第一条线段,其余部分被完全忽略。
  • 旋转无反应:调用rotate_3d_points后未将返回的旋转结果赋值给曲线变量,原曲线数据从未更新。
  • 投影逻辑缺陷:固定比例的正交投影未考虑z轴深度影响,旋转后曲线极易超出屏幕范围。

修复后的完整代码

import pygame
from pygame.locals import *
from math import cos, sin, radians

def draw_3d_lines(screen, color, points_list, distance=500):
    for i in range(len(points_list) - 1):
        x1, y1, z1 = points_list[i]
        x2, y2, z2 = points_list[i + 1]

        # 透视投影:根据z轴深度动态缩放,避免超出屏幕
        scale1 = distance / (distance + z1) if (distance + z1) != 0 else 1
        scale2 = distance / (distance + z2) if (distance + z2) != 0 else 1

        x1t = int(x1 * scale1 + screen.get_width() / 2)
        y1t = int(y1 * scale1 + screen.get_height() / 2)
        x2t = int(x2 * scale2 + screen.get_width() / 2)
        y2t = int(y2 * scale2 + screen.get_height() / 2)

        pygame.draw.line(screen, color, (x1t, y1t), (x2t, y2t), 2)

def rotate_3d_points(points_list, angle_x, angle_y, angle_z):
    angle_x = radians(angle_x)
    angle_y = radians(angle_y)
    angle_z = radians(angle_z)

    cos_x, sin_x = cos(angle_x), sin(angle_x)
    cos_y, sin_y = cos(angle_y), sin(angle_y)
    cos_z, sin_z = cos(angle_z), sin(angle_z)

    rotated_points = []
    for x, y, z in points_list:
        # 标准3D旋转顺序:X轴→Y轴→Z轴
        # 绕X轴旋转
        y_rot = y * cos_x - z * sin_x
        z_rot = y * sin_x + z * cos_x
        # 绕Y轴旋转
        x_rot = x * cos_y + z_rot * sin_y
        z_final = -x * sin_y + z_rot * cos_y
        # 绕Z轴旋转
        x_final = x_rot * cos_z - y_rot * sin_z
        y_final = x_rot * sin_z + y_rot * cos_z

        rotated_points.append((x_final, y_final, z_final))

    return rotated_points

def make_3d_curve(starting_point, ending_point, curve_point, step=0.01):
    points = []
    t = 0
    while t <= 1:
        # 二次贝塞尔曲线计算
        x = (1 - t)**2 * starting_point[0] + 2*(1-t)*t*curve_point[0] + t**2*ending_point[0]
        y = (1 - t)**2 * starting_point[1] + 2*(1-t)*t*curve_point[1] + t**2*ending_point[1]
        z = (1 - t)**2 * starting_point[2] + 2*(1-t)*t*curve_point[2] + t**2*ending_point[2]
        points.append((x, y, z))
        t += step
    return points

pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("3D Curve")

# 缩小初始坐标范围,避免曲线超出屏幕
start = [-150, -100, 0]
end = [150, 100, 0]
curve_ctrl = [100, 50, 200]
curve_points = make_3d_curve(start, end, curve_ctrl)

running = True
clock = pygame.time.Clock()

while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
        if event.type == KEYDOWN:
            # 将旋转结果赋值给曲线变量,更新数据
            if event.key == K_a:
                curve_points = rotate_3d_points(curve_points, 0, 5, 0)
            if event.key == K_d:
                curve_points = rotate_3d_points(curve_points, 0, -5, 0)
            if event.key == K_w:
                curve_points = rotate_3d_points(curve_points, 5, 0, 0)
            if event.key == K_s:
                curve_points = rotate_3d_points(curve_points, -5, 0, 0)
            if event.key == K_q:
                curve_points = rotate_3d_points(curve_points, 0, 0, 5)
            if event.key == K_e:
                curve_points = rotate_3d_points(curve_points, 0, 0, -5)

    screen.fill((0, 0, 0))
    draw_3d_lines(screen, (0,255,0), curve_points)
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

关键修复说明

  1. 完整绘制曲线:移除draw_3d_lines中循环内的return语句,确保所有线段都被渲染。
  2. 激活旋转功能:将旋转后的点列表重新赋值给curve_points,让操作真正作用于曲线数据。
  3. 透视投影优化:根据z轴深度动态调整缩放比例,既避免曲线超出屏幕,又增强3D视觉层次感。
  4. 修正旋转逻辑:采用标准的3D旋转顺序和矩阵计算,让旋转操作符合直觉。
  5. 调整初始坐标:缩小初始点的数值范围,确保曲线初始状态完整显示在屏幕内。

内容的提问来源于stack exchange,提问作者phoenixorigamiprogrammer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 20:15:42