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

使用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)范围内,尺寸过小,经过透视投影后所有顶点的屏幕坐标几乎重合,呈现为白点。
  2. 窗口放大时,没有调整立方体的缩放逻辑,导致立方体不会随窗口变大。

修复方案

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 01:27:14