Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Python turtle 3d soft render (+WASD movement and camera rotation)
"""
Черепашка вміє в 3D
Управління:
- стрілочки -- поворот
- WASD -- рух
"""
import turtle
import math
from math import sin, cos, pi
import time
import random
from collections import deque
turtle.tracer(0, 0)
turtle.bgcolor('black')
SQ = [(-1, -1), (-1, 1), (1, 1), (1, -1)]
Nlines = 10
size = 200
figure = [(x*size, y*size) for x, y in SQ]
camAngle = 1.3
camAngleSpeed = 0
camX = 131
camY = 472
def cam_left(ang=0.1):
global camAngle, camAngleSpeed, camSpeed
camAngleSpeed += ang/1000
camSpeed = 0
#camAngle += ang
redraw()
def cam_forward(speed=10, ang=math.pi/2):
global camX, camY, camAngleSpeed
#camAngleSpeed = 0
camX -= speed*math.sin(camAngle-ang)
camY -= speed*math.cos(camAngle-ang)
print(camX, camY, camAngle)
redraw()
turtle.onkeypress(lambda: cam_left(-0.1), "Left")
turtle.onkeypress(lambda: cam_left(0.1), "Right")
turtle.onkeypress(lambda: cam_forward(10), "Up")
turtle.onkeypress(lambda: cam_forward(10), "w")
turtle.onkeypress(lambda: cam_forward(-10), "Down")
turtle.onkeypress(lambda: cam_forward(-10), "s")
turtle.onkeypress(lambda: cam_forward(10, 0), "d")
turtle.onkeypress(lambda: cam_forward(10, math.pi), "a")
turtle.listen()
t1 = turtle.Turtle()
t1.penup()
t1.shapesize(3)
t1.color('white')
def rotated(x, y, angle, center=(0, 0)):
sin_, cos_ = math.sin(angle), math.cos(angle)
x0, y0 = center
newx = x0 + (x-x0)*sin_ + (y-y0)*cos_
newy = y0 + (x-x0)*cos_ - (y-y0)*sin_
return (newx, newy)
def perspective(x, y, z=0, camera=None, f=500):
"""
Perspective transformation. XY is horizontal
plane. Object Z is zero by default, change it if
you want to elevate object above the plane
"""
if camera:
xc, yc, zc = camera
else:
xc, yc, zc = camX, camY, 100
h = y - yc
if y == yc:
# todo: return something better
return (0, 0)
r = f/(y - yc)
return ((xc - x)*r, -(zc - z)*r)
def view(x, y, z=0):
newx, newy = rotated(x, y, camAngle,
center=(camX, camY))
return perspective(newx, newy, z)
def line(x1, y1, x2, y2, t):
t.penup()
t.goto(x1, y1)
t.pendown()
t.goto(x2, y2)
t.penup()
random_fig = deque(maxlen=100)
def redraw():
t1.clear()
t1.color('white')
t1.pensize(1)
for i in range(Nlines+1):
x1, y1 = view(size*(SQ[0][0] + i*2/Nlines),
SQ[0][1]*size)
x2, y2 = view(size*(SQ[1][0] + i*2/Nlines),
SQ[1][1]*size)
line(x1,y1,x2,y2,t1)
x1, y1 = view(size*(SQ[1][0]),
size*(SQ[1][1] - i*2/Nlines))
x2, y2 = view(size*(SQ[2][0]),
size*(SQ[2][1] - i*2/Nlines))
line(x1,y1,x2,y2,t1)
t1.penup()
if random_fig:
x,y,z,_ = random_fig[0]
t1.goto(*view(x,y,z))
t1.pendown()
t1.pensize(3)
for x, y, z, color in random_fig:
if not color:
color = 'white'
t1.color(color)
t1.goto(*view(x, y, z))
t1.penup()
redraw()
tstart = real_start = time.time()
while True:
camAngle += camAngleSpeed
if time.time() > tstart + 0.05:
tstart = time.time()
dt = tstart - real_start
random_fig.append((
size*sin(dt*3),
size*cos(dt*5),
size/2+size/2*sin(dt),
(random.random(), random.random(), 0)
))
redraw()
turtle.update()
@danbst
Copy link
Author

danbst commented Oct 1, 2021

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment