Close

Flattest LED Cube

A project log for Playing with MicroPython on the ESP

Instant gratification on the ESP8266 and ESP-32

Hari WigunaHari Wiguna 05/18/2019 at 13:290 Comments
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