使用Pygame制作3D旋转立方体仅显示小白点问题求助
Pygame 3D立方体显示异常修复
问题描述
使用Pygame制作可旋转3D立方体时,程序运行后仅显示一个旋转的小白点,放大窗口后立方体也不会随之变大。
原始代码
import pygame from pygame.locals import * from math import sin, cos pygame.init() screen = pygame.display.set_mode((800, 600)) # 定义立方体顶点 vertices = [(x, y, z) for x in (-1, 1) for y in (-1, 1) for z in (-1, 1)] edges = [(0, 1), (1, 3), (3, 2), (2, 0), (4, 5), (5, 7), (7, 6), (6, 4), (0, 4), (1, 5), (2, 6), (3, 7)] # 定义旋转函数 def rotate(x, y, angle): return x*cos(angle) - y*sin(angle), x*sin(angle) + y*cos(angle) # 初始化旋转角度 angle_x, angle_y, angle_z = 0, 0, 0 # 主循环 while True: for event in pygame.event.get(): if event.type == QUIT: pygame.quit() exit() # 清空屏幕 screen.fill((0, 0, 0)) # 对顶点应用旋转 rotated = [] for x, y, z in vertices: # 绕X轴旋转 y, z = rotate(y, z, angle_x) # 绕Y轴旋转 x, z = rotate(x, z, angle_y) # 绕Z轴旋转 x, y = rotate(x, y, angle_z) # 透视投影 f = 200 scale = f / (f - z) x, y = x*scale, y*scale # 转换为屏幕坐标 x, y = int(x + screen.get_width() / 2), int(y + screen.get_height() / 2) rotated.append((x, y)) # 绘制棱边 for i, j in edges: pygame.draw.line(screen, (255, 255, 255), rotated[i], rotated[j], 2) # 更新旋转角度 angle_x += 0.01 angle_y += 0.02 angle_z += 0.03 # 更新屏幕显示 pygame.display.flip()
问题原因
- 立方体原始顶点仅在
(-1,1)范围内,尺寸过小,经过透视投影后所有顶点的屏幕坐标几乎重合,呈现为白点。 - 窗口放大时,没有调整立方体的缩放逻辑,导致立方体不会随窗口变大。
修复方案
1. 放大立方体基础尺寸
给原始顶点乘以一个缩放系数(比如100),让立方体本身具备足够的尺寸:
# 修改顶点定义,乘以100放大尺寸 vertices = [(x*100, y*100, z*100) for x in (-1, 1) for y in (-1, 1) for z in (-1, 1)]
2. 可选:适配窗口大小变化(支持窗口缩放)
如果需要窗口可调整大小,添加窗口resize事件处理,更新屏幕尺寸,并让透视焦距随窗口适配:
# 初始化时设置窗口为可缩放 screen = pygame.display.set_mode((800, 600), RESIZABLE) # 在事件循环中添加resize处理 for event in pygame.event.get(): if event.type == QUIT: pygame.quit() exit() # 处理窗口缩放 if event.type == VIDEORESIZE: screen = pygame.display.set_mode((event.w, event.h), RESIZABLE)
同时可以把透视焦距f调整为和窗口高度关联的数值,比如f = screen.get_height() * 0.8,让投影效果随窗口适配。
修复后的完整代码
import pygame from pygame.locals import * from math import sin, cos pygame.init() # 设置可缩放窗口 screen = pygame.display.set_mode((800, 600), RESIZABLE) # 放大立方体顶点尺寸 vertices = [(x*100, y*100, z*100) for x in (-1, 1) for y in (-1, 1) for z in (-1, 1)] edges = [(0, 1), (1, 3), (3, 2), (2, 0), (4, 5), (5, 7), (7, 6), (6, 4), (0, 4), (1, 5), (2, 6), (3, 7)] def rotate(x, y, angle): return x*cos(angle) - y*sin(angle), x*sin(angle) + y*cos(angle) angle_x, angle_y, angle_z = 0, 0, 0 while True: for event in pygame.event.get(): if event.type == QUIT: pygame.quit() exit() # 处理窗口缩放 if event.type == VIDEORESIZE: screen = pygame.display.set_mode((event.w, event.h), RESIZABLE) screen.fill((0, 0, 0)) rotated = [] for x, y, z in vertices: y, z = rotate(y, z, angle_x) x, z = rotate(x, z, angle_y) x, y = rotate(x, y, angle_z) # 透视焦距随窗口高度适配 f = screen.get_height() * 0.8 scale = f / (f - z) x, y = x*scale, y*scale x, y = int(x + screen.get_width() / 2), int(y + screen.get_height() / 2) rotated.append((x, y)) for i, j in edges: pygame.draw.line(screen, (255, 255, 255), rotated[i], rotated[j], 2) angle_x += 0.01 angle_y += 0.02 angle_z += 0.03 pygame.display.flip()
内容的提问来源于stack exchange,提问作者Mico Tongco
相关产品推荐
相关产品推荐

