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()
关键修复说明
- 完整绘制曲线:移除
draw_3d_lines中循环内的return语句,确保所有线段都被渲染。 - 激活旋转功能:将旋转后的点列表重新赋值给
curve_points,让操作真正作用于曲线数据。 - 透视投影优化:根据z轴深度动态调整缩放比例,既避免曲线超出屏幕,又增强3D视觉层次感。
- 修正旋转逻辑:采用标准的3D旋转顺序和矩阵计算,让旋转操作符合直觉。
- 调整初始坐标:缩小初始点的数值范围,确保曲线初始状态完整显示在屏幕内。
内容的提问来源于stack exchange,提问作者phoenixorigamiprogrammer
相关产品推荐
相关产品推荐

