python - pygame中的3D投影
问题描述
我正在尝试创建一个简单的立方体 3d 渲染。正如 Coding Train 的这段视频: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], [250], [1]]))
points.append(np.array([[400], [350], [1]]))
projectionMatrix = np.array([[1, 0, 0],
[0, 1, 0]])
while True:
clock.tick(30)
screen.fill((0,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, 0.5, 1]))
points.append(np.matrix([-0.5, -0.5, 1]))
定义从范围[-1, 1] 到窗口空间的投影矩阵:
projectionMatrix = np.matrix([[height/2, 0, width/2],
[0, height/2, height/2]])
指定一个 3x3 旋转矩阵:
rotation = np.array([[math.cos(angle), -math.sin(angle), 0],
[math.sin(angle), math.cos(angle), 0],
[0, 0, 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, 0.5, 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, -0.5, 1]))
projectionMatrix = np.matrix([[height/2, 0, width/2],
[0, height/2, height/2]])
while True:
clock.tick(30)
screen.fill((0,0,0))
rotation = np.matrix([[math.cos(angle), -math.sin(angle), 0],
[math.sin(angle), math.cos(angle), 0],
[0, 0, 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()
推荐阅读
- javascript - 无法访问事件处理程序方法中的全局变量(javascript)
- mysql - 为什么作者使用了内连接而不是左连接?
- graphql - GraphQL 那么是否可以根据查询参数确定将动态返回的类型?
- django-rest-framework - DRF 序列化继承模型
- clang - 什么是 LLVM X 射线修补?
- next.js - Next.js 向 _document.js 添加有条件的标题元素
- amazon-web-services - 如何使用 javascript 将 AWS Lambda 添加到 VPC
- c# - 如何计算像 MD5(str1+ MD5(str2+ str3)) 这样的哈希值
- c# - 更新条目时出错。有关详细信息,请参阅内部异常有很多关系
- python-3.x - Python 3 TypeError:'int' object is not callable,但这里有什么问题?