Почему возникает искажение, когда куб находится на краю экрана?

#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()