Page 1 of 1
A Basic 3D Wireframe Implementation in LÖVE
Posted: Mon Dec 24, 2012 8:48 am
by rexjericho
Here's a project that I've sort of given up on. I attempted to implement a wireframe renderer using this guide:
http://www.kmjn.org/notes/3d_rendering_intro.html
Unfortunately my implementation is super horribly innefficient, but it works for simple shapes. I may revisit/redo this project in the future. There are so many things I would change.
I've attached a demo love file of a cube rotating about a random axis. Check it out. Let me know if you have any questions/criticisms. If you take a peek at the source, pretty much all the magic happens in the project() function and the camera table. Knowing a bit about vector/matrix math and 3d geometry may help.
- Ink89.png (32.23 KiB) Viewed 390 times
usage:
move camera side to side, up/down, in/out:
w,a,s,d,r,f
rotate camera on it's own x,y,z axis:
up, left, down, right, lshift, enter
Re: A Basic 3D Wireframe Implementation in LÖVE
Posted: Tue Dec 25, 2012 3:45 am
by Jasoco
Interesting. I don't really understand the matrix stuff. My 3D stuff just uses simple math to do the same thing. It runs through every single visible point every frame and calculates its 2D location every frame and is capable of doing this...
- ss.png (61.88 KiB) Viewed 3465 times
Without slowdown.
Code: Select all
function point3d(x, y, z, cam)
local cam = cam or camera
--3D Calculations are done here!!!!
local xy, xz, yz, yx, zx, zy, scale, dist, rx, ry, rz
rx = cam.x + x
ry = cam.y + y
rz = cam.z + z
xy = cx*ry - sx*rz
xz = sx*ry + cx*rz
yz = cy*xz - sy*rx
yx = sy*xz + cy*rx
zx = cz*yx - sz*xy
zy = sz*yx + cz*xy
scale = focal/(focal + yz)
rx = zx*scale
ry = zy*scale
dist = yz
return rx, ry, dist, scale
end
You basically use this to find out where each visible triangle is on screen, sort them by their distance and loop through them.
Re: A Basic 3D Wireframe Implementation in LÖVE
Posted: Sun Dec 30, 2012 6:06 am
by rexjericho
Thanks! This helped a lot. I didn't realize that the calculations were actually so simple. Multiplying the matrices together was the super innefficient part, so I ended up expanding them out by hand, and only calculating what was needed. This got rid of a tonne of unnecessary calculations that were being performed by the matrix multiplications
Code: Select all
-- vertex coordinates
local x = point.x
local y = point.y
local z = point.z
-- for camera perspective transform
local A11 = 2*cam.near/cam.width
local A22 = 2*cam.near/cam.height
local A33 = -(cam.far + cam.near)/(cam.far - cam.near)
local A34 = -(2*cam.far*cam.near)/(cam.far - cam.near)
-- for camera look transform
local B11 = cam.u.x -- camera's x axis
local B12 = cam.u.y
local B13 = cam.u.z
local B21 = cam.v.x -- camera's y axis
local B22 = cam.v.y
local B23 = cam.v.z
local B31 = cam.n.x -- camera's z axis
local B32 = cam.n.y
local B33 = cam.n.z
-- for camera perspective transform
local C14 = -cam.position.x
local C24 = -cam.position.y
local C34 = -cam.position.z
-- calculate vertex view space
local newx = A11*B11*x + A11*B12*y + A11*B13*z + A11*B11*C14 + A11*B12*C24 + A11*B13*C34
local newy = A22*B21*x + A22*B22*y + A22*B23*z + A22*B21*C14 + A22*B22*C24 + A22*B23*C34
local newz = A33*B31*x + A33*B32*y + A33*B33*z + A33*B31*C14 + A33*B32*C24 + A33*B33*C34 + A34
local neww = 1 - B31*x - B32*y - B33*z - B31*C14 - B32*C24 - B33*C34
-- normalize coordinates by dividing by homogenous coordinate neww
local wr = 1/neww
local newx = newx*wr
local newy = newy*wr
local newz = newz*wr
-- projected x and y coordinates
local projx = 0.5*newx*cam.width + 0.5*cam.width
local projy = 0.5*newy*cam.height + 0.5*cam.height
I went from being able to get 3 cubes on screen to 216! 18 rectangle draws to 1296, a massive improvement. I know there is still so much more that I can do to optimize my code, so I'll have to work on that for a while.
- V9qyN.png (55.68 KiB) Viewed 388 times
Re: A Basic 3D Wireframe Implementation in LÖVE
Posted: Sun Dec 30, 2012 3:12 pm
by arundel
Wow, this 3d wireframe and cube renderer looks promising. Good job.