如何从头开始在 pygame 3d 引擎中移动相机?
How to make camera movement in a pygame 3d engine from scratch?
我不熟悉矩阵和矩阵 t运行sformations 和其他东西。我正在使用 2d 在 pygame 中制作自己的 3d 引擎,但我 运行 遇到了问题。我无法让我的引擎实现相机移动,它只能进行相机旋转。这是我的代码:
window.py: 自定义 window class
from .general_imports import *
class Py3dWindow:
def __init__(self, title=None, width=800, height=600,):
self.title = title
self.window = None
self.width = width
self.height = height
self.meshes = []
self.events_assinged = False
self.projection_matrix = np.matrix([
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
])
print(self.projection_matrix)
self.camera = [
[0, 0, 0, 0],
[0, 0, 0],
75, # fov
1, # near
1000 # far
]
def add_mesh(self, mesh):
self.meshes.append(mesh)
def translate_matrix(self):
angle_x = math.radians(self.camera[1][0])
angle_y = math.radians(self.camera[1][1])
angle_z = math.radians(self.camera[1][2])
pos_x = self.camera[0][0]
pos_y = self.camera[0][1]
pos_z = self.camera[0][2]
rotation_z = np.matrix([
[int(np.cos(angle_z)), -int(np.sin(angle_z)), 0, 0],
[int(np.sin(angle_z)), int(np.cos(angle_z)), 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
],)
rotation_y = np.matrix([
[int(np.cos(angle_y)), 0, int(np.sin(angle_y))],
[0, 1, 0, 0],
[-int(np.sin(angle_y)), 0, int(np.cos(angle_y))],
[0, 0, 0, 1]
])
rotation_x = np.matrix([
[1, 0, 0, 0],
[0, int(np.cos(angle_x)), -int(np.sin(angle_x)), 0],
[0, int(np.sin(angle_x)), int(np.cos(angle_x)), 0],
[0, 0, 0, 1],
])
position_matrix = np.matrix([
[1, 0, 0, pos_x],
[0, 1, 0, pos_y],
[0, 0, 1, pos_z],
[0, 0, 0, 1],
])
self.projection_matrix = np.dot(rotation_z, np.dot(rotation_y, rotation_x)) * position_matrix
print(self.projection_matrix)
def init_window(self):
pygame.init()
self.window = pygame.display.set_mode((self.width, self.height), pygame.RESIZABLE)
pygame.display.set_caption(self.title)
self.running = False
def run(self,):
self.running = True
while self.running:
self.draw()
self.events(pygame.event.get())
self.update()
self.translate_matrix()
pygame.quit()
def events(self, events):
for event in events:
if event.type == pygame.QUIT:
self.running = False
if self.events_assinged:
self._events(events)
def update(self,):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
def draw(self,):
self.window.fill((0, 0, 0))
for mesh in self.meshes:
mesh.draw(self.window)
pygame.display.update()
time.sleep(0.001)
def on_events(self, func):
self._events = func
self.events_assinged = True
def on_update(self, func):
self.update = lambda: func()
def on_draw(self, func):
self.draw = lambda: func()
mesh.py:网格class
from .general_imports import *
class Mesh:
def __init__(self, parnet):
self.points = []
self.parent = parnet
def add_point(self, position):
position = [position[0] * 100, position[1] * 100, position[2] * 100, 1]
self.points.append(np.matrix(position))
def draw(self, window):
for point in self.points:
p = (point - self.parent.camera[0])
p = np.reshape(p, (4, 1))
projection = np.dot(self.parent.projection_matrix, p)
projection = projection.tolist()
x = projection[0][0]
y = projection[1][0]
pygame.draw.circle(window, (255, 255, 255), (int(x) + window.get_width() / 2 - 100, int(y) + window.get_width() / 2- 100) , 1)
demo.py:演示
# Py3D demo
from Py3D.__init__ import *
import random
win = Py3dWindow(title="Py3D")
win.init_window()
mesh_ = Mesh(win)
side = 1
for i in range(-side, side):
for j in range(-side, side):
for k in range(-side, side):
mesh_.add_point((i, j, k))
win.add_mesh(mesh_)
def move(events):
for i in events:
if i.type == 771:
if i.text == 'w':
win.camera[0][2] -= 1
if i.text == 's':
win.camera[0][2] += 1
if i.text == 'a':
win.camera[0][0] -= 1
if i.text == 'd':
win.camera[0][0] += 1
def rotate():
win.camera[1][0] = 45
win.camera[1][1] = 45
win.camera[1][2] = 45
win.on_events(move)
win.on_update(rotate)
win.run()
错误
ValueError: shapes (4,4) and (1,4) not aligned: 4 (dim 1) != 1 (dim 0)
我找到的解决方案
在translate_matrix函数中,我忘记在rotation_y中为整个数组添加四个索引。而已!效果很好!
正如您所指出的,在 translate_matrix
函数中,您的 rotation_y
变量声明不正确:
rotation_y = np.matrix([
[int(np.cos(angle_y)), 0, int(np.sin(angle_y))], # <--- missing an item
[0, 1, 0, 0],
[-int(np.sin(angle_y)), 0, int(np.cos(angle_y))], # <--- missing an item
[0, 0, 0, 1]
])
第一项和第三项只声明了3项,而第二项和第三项以及rotation_x
和rotation_z
的所有项都声明了4项。显然这行不通,因为矩阵应该是矩形的。
我不熟悉矩阵和矩阵 t运行sformations 和其他东西。我正在使用 2d 在 pygame 中制作自己的 3d 引擎,但我 运行 遇到了问题。我无法让我的引擎实现相机移动,它只能进行相机旋转。这是我的代码:
window.py: 自定义 window class
from .general_imports import *
class Py3dWindow:
def __init__(self, title=None, width=800, height=600,):
self.title = title
self.window = None
self.width = width
self.height = height
self.meshes = []
self.events_assinged = False
self.projection_matrix = np.matrix([
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
])
print(self.projection_matrix)
self.camera = [
[0, 0, 0, 0],
[0, 0, 0],
75, # fov
1, # near
1000 # far
]
def add_mesh(self, mesh):
self.meshes.append(mesh)
def translate_matrix(self):
angle_x = math.radians(self.camera[1][0])
angle_y = math.radians(self.camera[1][1])
angle_z = math.radians(self.camera[1][2])
pos_x = self.camera[0][0]
pos_y = self.camera[0][1]
pos_z = self.camera[0][2]
rotation_z = np.matrix([
[int(np.cos(angle_z)), -int(np.sin(angle_z)), 0, 0],
[int(np.sin(angle_z)), int(np.cos(angle_z)), 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
],)
rotation_y = np.matrix([
[int(np.cos(angle_y)), 0, int(np.sin(angle_y))],
[0, 1, 0, 0],
[-int(np.sin(angle_y)), 0, int(np.cos(angle_y))],
[0, 0, 0, 1]
])
rotation_x = np.matrix([
[1, 0, 0, 0],
[0, int(np.cos(angle_x)), -int(np.sin(angle_x)), 0],
[0, int(np.sin(angle_x)), int(np.cos(angle_x)), 0],
[0, 0, 0, 1],
])
position_matrix = np.matrix([
[1, 0, 0, pos_x],
[0, 1, 0, pos_y],
[0, 0, 1, pos_z],
[0, 0, 0, 1],
])
self.projection_matrix = np.dot(rotation_z, np.dot(rotation_y, rotation_x)) * position_matrix
print(self.projection_matrix)
def init_window(self):
pygame.init()
self.window = pygame.display.set_mode((self.width, self.height), pygame.RESIZABLE)
pygame.display.set_caption(self.title)
self.running = False
def run(self,):
self.running = True
while self.running:
self.draw()
self.events(pygame.event.get())
self.update()
self.translate_matrix()
pygame.quit()
def events(self, events):
for event in events:
if event.type == pygame.QUIT:
self.running = False
if self.events_assinged:
self._events(events)
def update(self,):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
def draw(self,):
self.window.fill((0, 0, 0))
for mesh in self.meshes:
mesh.draw(self.window)
pygame.display.update()
time.sleep(0.001)
def on_events(self, func):
self._events = func
self.events_assinged = True
def on_update(self, func):
self.update = lambda: func()
def on_draw(self, func):
self.draw = lambda: func()
mesh.py:网格class
from .general_imports import *
class Mesh:
def __init__(self, parnet):
self.points = []
self.parent = parnet
def add_point(self, position):
position = [position[0] * 100, position[1] * 100, position[2] * 100, 1]
self.points.append(np.matrix(position))
def draw(self, window):
for point in self.points:
p = (point - self.parent.camera[0])
p = np.reshape(p, (4, 1))
projection = np.dot(self.parent.projection_matrix, p)
projection = projection.tolist()
x = projection[0][0]
y = projection[1][0]
pygame.draw.circle(window, (255, 255, 255), (int(x) + window.get_width() / 2 - 100, int(y) + window.get_width() / 2- 100) , 1)
demo.py:演示
# Py3D demo
from Py3D.__init__ import *
import random
win = Py3dWindow(title="Py3D")
win.init_window()
mesh_ = Mesh(win)
side = 1
for i in range(-side, side):
for j in range(-side, side):
for k in range(-side, side):
mesh_.add_point((i, j, k))
win.add_mesh(mesh_)
def move(events):
for i in events:
if i.type == 771:
if i.text == 'w':
win.camera[0][2] -= 1
if i.text == 's':
win.camera[0][2] += 1
if i.text == 'a':
win.camera[0][0] -= 1
if i.text == 'd':
win.camera[0][0] += 1
def rotate():
win.camera[1][0] = 45
win.camera[1][1] = 45
win.camera[1][2] = 45
win.on_events(move)
win.on_update(rotate)
win.run()
错误
ValueError: shapes (4,4) and (1,4) not aligned: 4 (dim 1) != 1 (dim 0)
我找到的解决方案
在translate_matrix函数中,我忘记在rotation_y中为整个数组添加四个索引。而已!效果很好!
正如您所指出的,在 translate_matrix
函数中,您的 rotation_y
变量声明不正确:
rotation_y = np.matrix([
[int(np.cos(angle_y)), 0, int(np.sin(angle_y))], # <--- missing an item
[0, 1, 0, 0],
[-int(np.sin(angle_y)), 0, int(np.cos(angle_y))], # <--- missing an item
[0, 0, 0, 1]
])
第一项和第三项只声明了3项,而第二项和第三项以及rotation_x
和rotation_z
的所有项都声明了4项。显然这行不通,因为矩阵应该是矩形的。