So I was trying to make a 3d engine from scratch in Python when i tried to rotate the plane. All axes were fine as predefined rotations in 3d space, but when updating rotation in the code, only the x and z axes were working. But as for the y-axis, when updating rotation, looked like an octagonal origami mess.
Though it looks fine, it keeps on jittering on and on . I can't show you the video but you most likely get the idea.
Here's all the code which I have made so far:
# imports
import pygame as pg
from vec import Vec3, Vec2
from math import sin, cos, tau
pg.init()
# screen
screen_dim: tuple[int, int] = (480, 360)
screen = pg.display.set_mode(screen_dim)
origin: Vec2 = Vec2(screen_dim[0] / 2, screen_dim[1] / 2)
# undertale
clock = pg.time.Clock()
delta: float = 1000 / clock.tick(60)
running: bool = True
# camera
class Camera:
def __init__(self, pos: Vec3, fov: float) -> None:
self.pos: Vec3 = pos
self.fov: float = fov
camera: Camera = Camera(Vec3(0, 0, -1), 120)
# vertex
class Vertex:
def __init__(self, pos: Vec3) -> None:
self.pos: Vec3 = pos
vertices = []
# creation
def create_vertex(pos: Vec3) -> None:
vertices.append(Vertex(pos))
def create_line(pos1: Vec3, pos2: Vec3) -> None:
vertices.append(Vertex(pos1))
vertices.append(Vertex(pos2))
def create_plane(pos: Vec3, dim: Vec2, rot: Vec3) -> None:
for i in range(-1, 2, 2):
for j in range(-1, 2, 2):
x_pos: float = dim.x / 2 * i
y_pos: float = dim.y / 2 * j
z_pos: float = 0
vertices.append(Vertex(Vec3(
pos.x + \
x_pos*(cos(rot.y)*cos(rot.z)) + \
y_pos*(cos(rot.z)*sin(rot.x)*sin(rot.y) - cos(rot.x)*sin(rot.z)) + \
z_pos*(cos(rot.x)*cos(rot.z)*sin(rot.y) + sin(rot.x)*sin(rot.z)), # y * z
pos.y + \
x_pos*(cos(rot.y)*sin(rot.z)) + \
y_pos*(cos(rot.x)*cos(rot.z) + sin(rot.x)*sin(rot.y)*sin(rot.z)) + \
z_pos*(cos(rot.x)*sin(rot.y)*sin(rot.z) - cos(rot.z)*sin(rot.x)), # x * z
pos.z + \
x_pos*(-sin(rot.y)) + \
y_pos*(cos(rot.y)*sin(rot.x)) + \
z_pos*(cos(rot.x)*cos(rot.y)) # x * y
)))
def calculate_vertex(vertex: Vertex) -> tuple[float, float]:
return (origin.x + (vertex.pos.x-camera.pos.x) * camera.fov/(vertex.pos.z-camera.pos.z),
origin.y + (vertex.pos.y-camera.pos.y) * camera.fov/(vertex.pos.z-camera.pos.z))
n: Vec3 = Vec3(0, 0, 0)
# drawing
def draw_vertex(vert_id: int, color: str, radius: float) -> None:
# NOTE: "vert_id" refers to the index of a vertex in th list
vertex: Vertex = vertices[vert_id]
pg.draw.circle(screen, color, calculate_vertex(vertex), radius)
def draw_line(vert_id: int, other_vert_id: int, color: str, width: float) -> None:
vertex: Vertex = vertices[vert_id]
other_vertex: Vertex = vertices[other_vert_id]
pg.draw.line(
screen, color,
calculate_vertex(vertex),
calculate_vertex(other_vertex),
width
)
# wireframe
def draw_plane_wf(vert_id: int, color: str, width: float) -> None:
if width == 0:
raise ValueError('it has wf for a reason')
pg.draw.polygon(
screen, color,
[calculate_vertex(vertices[vert_id]),
calculate_vertex(vertices[vert_id + 2]),
calculate_vertex(vertices[vert_id + 1]),
calculate_vertex(vertices[vert_id + 3])],
width
)
# filled in color
def draw_plane(vert_id, color: str) -> None:
vertex: Vertex = vertices[vert_id]
create_line(Vec3(1, 1, 1), Vec3(-1, -1, 1))
create_plane(Vec3(0, 0, 1), Vec2(1, 1), Vec3.zero())
while running:
delta: float = clock.tick(60) / 1000
# loop
for ev in pg.event.get():
if ev.type == pg.QUIT:
running = False
# update
del vertices[2:-1]
create_plane(Vec3(0, 0, 1), Vec2(1, 1), n)
n += Vec3(0, tau, 0) * delta
# draw
screen.fill('black')
for i in range(len(vertices)):
draw_vertex(i, 'white', 2)
draw_line(0, 1, 'red', 1)
draw_plane_wf(2, 'green', 2)
pg.display.flip()
And also, only the y-axis is buggy when updating, not the other axes.
