This is part 2 of me walking through the process of software rendering 3D objects on Pico 8, click here for part 1. In this post I’m projecting a wireframe cube made up of triangles. Click here to give it a try.
The _init function now has 8 vertices for each of the points of the cube, and a new table called tris. This table holds 12 triangles, since each face of the cube is made of 2 triangles. There isn’t much reason for this yet, but rendering triangles is a much simpler process than quads and so will make life easier going forward. Each triangle is 3 points, and each point is an index into the verts table.
function _init()
--8 points of a cube
--these are in world space
--i.e. -1 to 1
verts={
{x=-1,y=-1,z=-1},
{x=-1,y= 1,z=-1},
{x= 1,y= 1,z=-1},
{x= 1,y=-1,z=-1},
{x=-1,y=-1,z= 1},
{x=-1,y= 1,z= 1},
{x= 1,y= 1,z= 1},
{x= 1,y=-1,z= 1}
}
--indexes into verts
--two triangles per cube face
tris={
--front
{1,2,3},{1,3,4},
--back
{8,7,6},{8,6,5},
--left
{5,6,2},{5,2,1},
--right
{4,3,7},{4,7,8},
--top
{5,1,4},{5,4,8},
--bottom
{2,6,7},{2,7,3}
}
pos={x=0,y=0,z=3}
end
The update method is unchanged.
function _update60()
if (btn(➡️)) pos.x+=.1
if (btn(⬅️)) pos.x-=.1
if (btn(⬇️)) pos.y+=.1
if (btn(⬆️)) pos.y-=.1
if (btn(❎)) pos.z+=.1
if (btn(🅾️)) pos.z-=.1
end
I’ve merged the three functions to project a point from the previous post. This function moves, projects and then converts to screen space in one.
--merged the functions from
--the previous post into one
function project(v)
--move
local x=v.x+pos.x
local y=v.y+pos.y
local z=v.z+pos.z
--project to screen
return {
x=(x/z+1)/2*128,
y=(y/z+1)/2*128
}
end
Now the _draw function first loops through the vertices, projecting each and then storing it in a new local table called proj. I do this because each point is referenced multiple times in the triangles. Projecting them all upfront means that it only happens once at the start of the frame.
I then loop through the triangles table, find the projected vertex for each point, and draw each of its lines.
function _draw()
cls()
--project all of the vertices
--first, since each is
--referenced by multiple
--triangles
local proj={}
for v in all(verts) do
add(proj,project(v))
end
--for each triangle, grab the
--projected vertex and draw
--the triangle
for t in all(tris) do
local a=proj[t[1]]
local b=proj[t[2]]
local c=proj[t[3]]
line(a.x,a.y,b.x,b.y,11)
line(b.x,b.y,c.x,c.y,11)
line(c.x,c.y,a.x,a.y,11)
end
print("x:"..pos.x,8)
print("y:"..pos.y,8)
print("z:"..pos.z,8)
end