#python-3.x #math #pygame #3d #rendering
Вопрос:
Я создал средство визуализации куба с нуля, используя pygame.Я следовал онлайн-руководству и переводил его на python и был довольно успешным, пока не начал играть с программой. Все работает нормально, однако я заметил, что когда куб находится дальше от центра, возникает сильный эффект искажения. Например, неоправданно большое искажение. Что-то не так с тем, как вычисляются лучи? (Клавиши со стрелками для перемещения камеры)
import pygame
width = 720
height = 480
red = (255, 0, 0)
white = (255, 255, 255)
black = (0,0,0)
screen = pygame.display.set_mode((width, height))
running = True
clock = pygame.time.Clock()
runSpeed = 30
cube = [0, 0, 0], [8, 0, 0], [8, 0, 8], [0, 0, 8], [0, 8, 0], [8, 8, 0], [8, 8, 8], [0, 8, 8]
cubeCoords = [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]
moveCubeCoords = [8, -4, -4]
camCoord = [0, 0, 0]
camSpeed = 1
canvasDis = 1
scale = 80
def coordConvert(x, y):
newX = (width / 2) x
newY = (height / 2) y
return newX, newY
def drawCircle(x, y):
pygame.draw.circle(screen, red, (x, y), 5)
def moveCube():
for i in range(len(cube)):
for e in range(3):
cube[i][e] = cube[i][e] moveCubeCoords[e]
def onEvent(event):
if event.key == pygame.K_UP:
camCoord[1] = camCoord[1] camSpeed
if event.key == pygame.K_DOWN:
camCoord[1] = camCoord[1] - camSpeed
if event.key == pygame.K_RIGHT:
camCoord[2] = camCoord[2] camSpeed
if event.key == pygame.K_LEFT:
camCoord[2] = camCoord[2] - camSpeed
print(camCoord)
def main():
pygame.init()
print("Initialized")
pygame.display.set_caption("Cube rendering")
moveCube()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYDOWN:
onEvent(event)
for i, point in enumerate(cube): # gets all coords of cube
pX = point[0] - camCoord[0]
pY = point[1] - camCoord[1]
pZ = point[2] - camCoord[2]
mpX = pZ / pX
mpY = pY / -pX # canvas Y deviation from origin
newCoords = coordConvert(mpX * scale, mpY * scale)
cubeCoords[i][0] = newCoords[0]
cubeCoords[i][1] = newCoords[1]
drawCircle(newCoords[0], newCoords[1])
for i in range(4): # Vert lines
pygame.draw.line(screen, black, (cubeCoords[i][0], cubeCoords[i][1]),
(cubeCoords[i 4][0], cubeCoords[i 4][1]), 2)
for i in range(3):# Bottom lines
pygame.draw.line(screen, black, (cubeCoords[i][0], cubeCoords[i][1]),
(cubeCoords[i 1][0], cubeCoords[i 1][1]), 2)
pygame.draw.line(screen, black, (cubeCoords[3][0], cubeCoords[3][1]),
(cubeCoords[0][0], cubeCoords[0][1]), 2)
for i in range(3): # Top lines
pygame.draw.line(screen, black, (cubeCoords[i 4][0], cubeCoords[i 4][1]),
(cubeCoords[i 5][0], cubeCoords[i 5][1]), 2)
#lazy lines
pygame.draw.line(screen, black, (cubeCoords[3][0], cubeCoords[3][1]),
(cubeCoords[0][0], cubeCoords[0][1]), 2)
pygame.draw.line(screen, black, (cubeCoords[7][0], cubeCoords[7][1]),
(cubeCoords[4][0], cubeCoords[4][1]), 2)
print(cubeCoords)
clock.tick(runSpeed)
pygame.display.update()
screen.fill(white)
if __name__ == '__main__':
main()
Комментарии:
1. Проверьте это . Рис. 2, вероятно, то, что вы видите..
2. @mikuszefski Даже если сторона куба не перпендикулярна камере, как показано на рисунке, будет ли этот эффект иметь место?
3. Я был бы удивлен, если бы для этого эффекта потребовался «перпендикуляр»
Ответ №1:
Единственное место, где правильно проецируется карта куба, — это центр куба. Изображения имеют искажения, и при просмотре их под любым другим углом они начинают искажаться.
Если вы хотите переместить плеер по области, вы можете сделать куб ДЕЙСТВИТЕЛЬНО большим, чтобы минимизировать искажения, поскольку проигрыватель не будет удаляться далеко от центра относительно куба. Это типично для игровых сред.
Вот объяснение проекции карты куба. http://wiki .polycount.com/wiki/Cube_map
Ответ №2:
То, что можно увидеть, называется искажением перспективы.
В любом случае вы можете упростить и очистить код:
import pygame
pygame.init()
window = pygame.display.set_mode((600, 400))
width, height = window.get_size()
clock = pygame.time.Clock()
cube = [-1, -1, -1], [1, -1, -1], [1, -1, 1], [-1, -1, 1], [-1, 1, -1], [1, 1, -1], [1, 1, 1], [-1, 1, 1]
edges = [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4), (0, 4), (1, 5), (2, 6), (3, 7)]
cam_coord, cam_speed = [0, 0, 0], 0.5
scale = 200
translate = [4, 0, 0]
for i in range(len(cube)):
for e in range(3):
cube[i][e] = translate[e]
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
cam_coord[1] -= (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * cam_speed
cam_coord[2] -= (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * cam_speed
cube_coords = []
for point in cube:
x = (width / 2) scale * (point[2] - cam_coord[2]) / (point[0] - cam_coord[0])
y = (height / 2) scale * (point[1] - cam_coord[1]) / (point[0] - cam_coord[0])
cube_coords.append((x, y))
window.fill((255, 255, 255))
for edge in edges:
pygame.draw.line(window, (0, 0, 0), cube_coords[edge[0]], cube_coords[edge[1]], 2)
for coord in cube_coords:
pygame.draw.circle(window, (255, 0, 0), coord, 5)
pygame.display.update()
pygame.quit()
exit()