Search code examples
pythonmath3dturtle-graphicspython-turtle

How to compensate for shepard tabletop illusion in 3D engine


I am creating a 3d engine in python using turtle. When you rotate the cube it looks like it is stretching even though i am pretty sure my code is correct.

import turtle
import time
import keyboard
import math

# Movement

horizontalRotation = 0
verticalRotation = 0
    
def moveX(t, distance):
    t.goto(t.xcor() + (distance + horizontalRotation), t.ycor() - distance/2 - verticalRotation)
def moveY(t, distance):
    t.goto(t.xcor(), t.ycor() + (distance - verticalRotation))
def moveZ(t, distance):
    t.goto(t.xcor() - (distance - horizontalRotation), t.ycor() - distance/2 - verticalRotation)
def moveNegX(t, distance):
    t.goto(t.xcor() + (distance - horizontalRotation), t.ycor() + distance/2 + verticalRotation)
def moveNegY(t, distance):
    t.goto(t.xcor(), t.ycor() - (distance - verticalRotation))
def moveNegZ(t, distance):
    t.goto(t.xcor() - (distance + horizontalRotation), t.ycor() + distance/2 + verticalRotation)

# End Movement; Functions

def drawCube(size):
    moveNegX(t, size)
    moveY(t, size)
    moveZ(t, size)
    moveNegY(t, size)
    moveNegZ(t, size)
    moveY(t, size)
    moveX(t, size)
    moveNegX(t, size)
    moveNegZ(t, size)
    moveZ(t, size)
    moveNegX(t, size)
    moveNegY(t, size)
    moveZ(t, size)
    moveNegX(t, size)
    moveX(t, size)

# End Functions

x = 2

w = turtle.Screen()
w.title("3D Graphics")

w.tracer(0)

t = turtle.Turtle()

def RenderLoop():
    t.hideturtle()
    t.pensize(5)
    t.fillcolor('grey')

    global horizontalRotation
    global verticalRotation

    t.penup()
    t.goto(t.xcor() + horizontalRotation, t.ycor() + verticalRotation)
    t.pendown()

    if keyboard.is_pressed('d'):
        horizontalRotation += x
    if keyboard.is_pressed('a'):
        horizontalRotation -= x
    if keyboard.is_pressed('w'):
        verticalRotation += x
    if keyboard.is_pressed('s'):
        verticalRotation -= x

    drawCube(100)

    w.update()
    t.reset()

while(True):
    RenderLoop()
    time.sleep(0.1)

The reason for this i think is the shepard tabletop illusion, but other 3d engines dont have this problem, how can i compensate for this? Thanks in advance.


Solution

  • Your problem has nothing to do with the shepard tabletop illusion (which is just an illusion that makes you think that two parallelograms are different when they are the same)

    The principle of a projection is to convert an n-dimension point into an m-dimensions point where m < n. If you're trying to do an orthographic projection, you'll have to convert the 3d coordinates of the vertices of your cube into 2d coordinates on your screen and then draw the edges on your screen by connecting those 2d points. To do the conversion, you can multiply the coordinates of a point by 2 rotation matrices (one for each axis you want to rotate around) and then you can simply ignore the z component to project it on the x-y-plane (your screen).

    2