Построение перспективной проекции трехмерного объекта. Фигура неправильно располагается

Можете помочь, фигура почему-то в углу появляется, в чем может быть проблема?

from tkinter import *
import math

def view_tr():
    d = 600 
    ro = 300 
    global teta
    global phi
    for i in range(len(vx)):
        vx[i] = round((wx[i] * (-1) * math.sin(teta)) + wy[i] * (math.cos(teta)))
        vy[i] = round((wx[i] * (-1) * math.cos(phi) * math.cos(teta)) - wy[i] * math.cos(phi) * math.sin(teta) + wz[i] * (math.sin(phi)))
        vz[i] = round((wx[i] * (-1) * math.sin(phi) * math.cos(teta)) - wy[i] * math.sin(phi) * math.sin(teta) - wz[i] * (math.cos(phi)) + ro)
        
        sx[i] = round(d * (vx[i] / vz[i])) + (ww / 2)
        sy[i] = round(d * (vy[i] / vz[i])) + (hh / 2)

        

def draw(): 
    c.create_line(vx[0], vy[0], vx[1], vy[1])
    c.create_line(vx[1], vy[1], vx[2], vy[2])
    c.create_line(vx[2], vy[2], vx[3], vy[3])
    c.create_line(vx[3], vy[3], vx[0], vy[0])
    c.create_line(vx[0], vy[0], vx[4], vy[4])
    c.create_line(vx[4], vy[4], vx[5], vy[5])
    c.create_line(vx[5], vy[5], vx[6], vy[6])
    c.create_line(vx[6], vy[6], vx[7], vy[7])
    c.create_line(vx[7], vy[7], vx[4], vy[4])
    c.create_line(vx[1], vy[1], vx[5], vy[5])
    c.create_line(vx[2], vy[2], vx[6], vy[6])
    c.create_line(vx[3], vy[3], vx[7], vy[7])
    
    
    
    

root = Tk() 
ww = 600
hh = 400
c = Canvas(root, width=ww, height=hh, bg='#0099ff')
c.pack()

teta = math.pi/4  
phi = math.pi/4

vx = [0, 0, 0, 0, 0, 0, 0, 0]
vy = [0, 0, 0, 0, 0, 0, 0, 0]
vz = [0, 0, 0, 0, 0, 0, 0, 0]

wx=[-50,50,50,-50,-50,50,50,-50]
wy=[-50,-50,50,50,-50,-50,50,50]
wz=[-50,-50,-50,-50,50,50,50,50]

sx = [0, 0, 0, 0, 0, 0, 0, 0]
sy = [0, 0, 0, 0, 0, 0, 0, 0]


view_tr()

def up():
    global teta
    global phi
    phi += 0.1
    c.create_rectangle(0,0,ww,hh,fill='#0099ff') 
    view_tr()
    draw()
    

def down() :
    global teta
    global phi
    phi -= 0.1
    c.create_rectangle(0,0,ww,hh,fill='#0099ff') 
    view_tr() 
    draw()
    
    

def left():
    global teta
    global phi
    teta -= 0.1
    c.create_rectangle(0,0,ww,hh,fill='#0099ff') 
    view_tr()
    draw() 
    

def right():
    global teta
    global phi
    teta += 0.1
    c.create_rectangle(0,0,ww,hh,fill='#0099ff') 
    view_tr()
    draw() 
    

b2 = Button(text='Лево', command = left, padx="70")
b2.pack(side=LEFT, fill=Y)
b4 = Button(text='Право', command = right, padx="70")
b4.pack(side=RIGHT, fill=Y)
b1 = Button(text='Вверх', command = up, pady="15")
b1.pack(side=TOP, fill=X)
b3 = Button(text='Вниз', command = down, pady="15")
b3.pack(side=BOTTOM, fill=X)

root.mainloop()

Ответы (1 шт):

Автор решения: insolor

В функции draw вы рисуете по объемным координатам (vx, vy), которые отсчитываются от нуля, а для canvas координата 0, 0 - это левый верхний угол. Нужно рисовать по экранным координатам (sx, sy), в них у вас начало координат смещается на середину экрана (к координатам по x и по y прибавляется половина ширины и высоты экрана соответственно):

sx[i] = round(d * (vx[i] / vz[i])) + (ww / 2)
sy[i] = round(d * (vy[i] / vz[i])) + (hh / 2)

Нужно в функции draw заменить все vx на sx и vy на sy:

def draw(): 
    c.create_line(sx[0], sy[0], sx[1], sy[1])
    c.create_line(sx[1], sy[1], sx[2], sy[2])
    c.create_line(sx[2], sy[2], sx[3], sy[3])
    c.create_line(sx[3], sy[3], sx[0], sy[0])
    c.create_line(sx[0], sy[0], sx[4], sy[4])
    c.create_line(sx[4], sy[4], sx[5], sy[5])
    c.create_line(sx[5], sy[5], sx[6], sy[6])
    c.create_line(sx[6], sy[6], sx[7], sy[7])
    c.create_line(sx[7], sy[7], sx[4], sy[4])
    c.create_line(sx[1], sy[1], sx[5], sy[5])
    c.create_line(sx[2], sy[2], sx[6], sy[6])
    c.create_line(sx[3], sy[3], sx[7], sy[7])

Результат:

Скриншот

Если нужна аксонометрическая (параллельная) проекция вместо перспективной, поменяйте вычисление экранных координат таким образом:

sx[i] = round(vx[i]) + (ww / 2)
sy[i] = round(vy[i]) + (hh / 2)

Результат:

Параллельная проекция

→ Ссылка