pygame中的3D投影

问题描述

我正在尝试创建一个简单的多维数据集3d渲染。就像这段来自编码火车的视频:https://www.youtube.com/watch?v=p4Iz0XJY-Qk是在第14分钟时。我被困在一点。由于我对所有这些都还很陌生,因此我不确定是什么原因导致了我的问题。当我启动项目时,多维数据集会按照我希望的方向旋转,但会从屏幕向左移动,看起来像是在做一个圆圈。

import pygame
import numpy as np
import os
import math

WHITE = (255,255,255)
width,height = 700,700
screen = pygame.display.set_mode((width,height))
clock = pygame.time.Clock()

points = []
angle = 0

points.append(np.array([[300],[250],[1]]))
points.append(np.array([[300],[350],[1]]))
points.append(np.array([[400],[1]]))

projectionMatrix = np.array([[1,0],[0,1,0]])

while True:
    clock.tick(30)
    screen.fill((0,0))

    rotation = np.array([[math.cos(angle),-math.sin(angle)],[math.sin(angle),math.cos(angle)]])

    for event in pygame.event.get():
            if event.type == pygame.QUIT:
                os._exit(1)

    for point in points:
        projected2d = np.dot(projectionMatrix,point)
        rotated = np.dot(rotation,projected2d)
        pygame.draw.circle(screen,WHITE,(int(rotated[0][0]),int(rotated[1][0])),5)

    angle += 0.01
    pygame.display.update()

我非常感谢您提供帮助,以帮助您了解为什么会发生这种情况以及如何解决它,以便它能够自动旋转。

解决方法

此代码中没有错误。这些点围绕左上方(0,0)旋转。请注意,在3D模式下,p5.js使用的坐标系不同于pygame

如果要围绕窗口中心旋转点,则在[-1,1]范围内定义点(标准化设备空间:

points.append(np.matrix([ 0.5,0.5,1]))
points.append(np.matrix([ 0.5,-0.5,1]))
points.append(np.matrix([-0.5,1]))

定义范围为[​​-1,1]到窗口空间的投影矩阵:

projectionMatrix = np.matrix([[height/2,width/2],[0,height/2,height/2]])

指定3x3旋转矩阵:

rotation = np.array([[math.cos(angle),-math.sin(angle),0],[math.sin(angle),math.cos(angle),1]])

首先旋转点,然后将其投影到窗口中

projected2d = projectionMatrix * rotation * point.reshape((3,1))

完整示例:

import pygame
import numpy as np
import os
import math

WHITE = (255,255,255)
width,height = 400,300
screen = pygame.display.set_mode((width,height))
clock = pygame.time.Clock()

points = []
angle = 0

points.append(np.matrix([ 0.5,1]))

projectionMatrix = np.matrix([[height/2,height/2]])

while True:
    clock.tick(30)
    screen.fill((0,0))

    rotation = np.matrix([[math.cos(angle),1]])

    for event in pygame.event.get():
            if event.type == pygame.QUIT:
                os._exit(1)

    for point in points:
        projected2d = projectionMatrix * rotation * point.reshape((3,1))
        pygame.draw.circle(screen,WHITE,(int(projected2d[0][0]),int(projected2d[1][0])),5)

    angle += 0.01
    pygame.display.update()