Learning how to do 3D to 2D projection from Daniel Shiffman of the coding train.
Rotation matrix in WikiPedia
# Rotating cube on MicroPython by Hari Wiguna
# Original code in P5 by Daniel Shiffman of The Coding Train
# v5. Faster by using less points and computing sin cos once
# v6. different rotation rate for x and z
# v7. Multiple effects
# v8. Rotate by small increments and put it back into the cube so we could chain effects
import machine, ssd1306, math
cube = []
ax = 0.2
ay = 0.2
az = 0.2
m = 70 # magnification
def setup_oled():
i2c = machine.I2C(scl=machine.Pin(5), sda=machine.Pin(4))
return ssd1306.SSD1306_I2C(64, 48, i2c)
def make_cube():
n = 3
d = 1/n
for z in range(n):
for x in range(n):
for y in range(n):
cube.append([-0.5 + x*d, -0.5 + y*d, -0.5 + z*d])
def mat_mul(tx, a):
out = []
for r in range(len(tx)):
tot = 0
for c in range(len(tx[r])):
tot += tx[r][c] * a[c]
out.append(tot)
return out
def rotate_on_x(p3, angle): # returns 1x3 matrix
sin = math.sin(angle)
cos = math.cos(angle)
rotx = [
[1, 0, 0],
[0, cos, -sin],
[0, sin, cos]
]
return mat_mul(rotx, p3)
def rotate_on_y(p3, angle): # returns 1x3 matrix
sin = math.sin(angle)
cos = math.cos(angle)
roty = [
[cos, 0, sin],
[0, 1, 0],
[-sin, 0, cos]
]
return mat_mul(roty, p3)
def rotate_on_z(p3, angle): # returns 1x3 matrix
sin = math.sin(angle)
cos = math.cos(angle)
rotz = [
[cos, -sin, 0],
[sin, cos, 0],
[0, 0, 1]
]
return mat_mul(rotz, p3)
def transform_3_to_2_with_perspective(p3):
distance = 2
z = 1 / (distance - p3[2])
pmatrix = [[z, 0, 0],
[0, z, 0]]
return mat_mul(pmatrix, p3)
def drawdot(oled, p3):
p2 = transform_3_to_2_with_perspective(p3)
oled.pixel(32 + int(p2[0] * m), 24 + int(p2[1] * m), 1)
def spinx(oled, count):
global ax, ay, az
for n in range(count):
oled.fill(0)
for i in range(len(cube)):
cube[i] = rotate_on_y(cube[i], ax)
drawdot(oled, cube[i])
oled.show()
def spiny(oled, count):
global ax, ay, az
for n in range(count):
oled.fill(0)
for i in range(len(cube)):
cube[i] = rotate_on_y(cube[i], ay)
drawdot(oled, cube[i])
oled.show()
def spinz(oled, count):
global ax, ay, az
for n in range(count):
oled.fill(0)
for i in range(len(cube)):
cube[i] = rotate_on_z(cube[i], az)
drawdot(oled, cube[i])
oled.show()
def tumble(oled, count):
global ax, ay, az
for n in range(count):
oled.fill(0)
for i in range(len(cube)):
p3 = rotate_on_y(cube[i], ax)
p3 = rotate_on_z(p3, az)
drawdot(oled, p3)
cube[i] = p3
oled.show()
def projection():
oled = setup_oled()
make_cube()
while True:
count = 10
spiny(oled, count)
spinz(oled, count)
tumble(oled, count)
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.