There are many JavaScript 3D libraries out there, such as THREE.js, but I wanted to challenge myself to write the neatest, most simple code that accomplishes rendering objects in 3D to a 2D screen. Ignoring comments, all the code that was necessary to build this to its current functionality is under 100 lines!
Simply include the source in your application's HTML, no downloading required:
<script src='https://joeiddon.github.io/zengine/zengine.js'></script>
or you can use the shorter git.io
redirect:
<script src='https://git.io/zengine.js'></script>
The main use of this library is obviously the rendering capabilities. This is covered below. However functions that are required to render are also available for use as part of the library. Some examples of these include: a dot product function, transformation matricies and distance functions. Feel free to use these but at the time of writing, no documentation has been made for them.
Prerequisites:
- All angles are in degrees.
- All distances are in arbitary units - relative to each other.
- The coordinate system has the
y-axis
going straight ahead,x-axis
to the right andz-axis
going straight up.
The main function - zengine.render()
- renders a world from the perspective of a camera to a HTML5 Canvas Element.
It has the format:
zengine.render(world, cam, canvas, wireframe, horizon, light);
Note that wireframe
, horizon
and light
can be set to their default values of: false
, Infinity
(not actually because the filtering step is skipped for efficiency) and the camera's point of view's vector by not passing them or through undefined
.
The world
is described by an array of faces.
Each face is itself an object with attributes:
Attribute | Meaning |
---|---|
verts |
array of vertexes as objecs (e.g. {x: 0, y: 0, z: 0} ) |
vect |
the face's unit vector (e.g. {x: 0, y: 1, z: 0} ) |
col |
color - if using shading, an object with attributes h, s, l else any CSS string |
This can be summarised by the following general-case format.
world = [{verts: [{x: ,y: ,z: }, {x: ,y: ,z: }, ...], vect: {x: ,y: ,z: }, col: }, ...]
The cam
parameter is an object with attributes:
Attribute | Meaning |
---|---|
x , y , z |
cooridinate in 3D Cartesian Geometry |
yaw |
rotation left to right |
pitch |
rotation up and down |
roll |
rotation about the "forward" axis |
fov |
the, horizontal, field of view, in degrees |
This can be seen in the following general-case format.
cam = {x: ,y: ,z: ,yaw: ,pitch: ,roll: ,fov: }
The canvas
parameter should be a HTML Canvas Element Object.
Calling this function will blank the canvas before drawing to it.
The wireframe
parameter takes a boolean indicating whether or not to draw just the outlines of each face. This also speeds up the rendering as face ordering is no longer required, and drawing to the Canvas is marginally faster.
The horizon
parameter takes a distance, in units relative to the world, for how far you can see. The purpose of this is to speed up rendering. If left undefined
, defaults to infinity.
The light
parameter is an object with attributes:
Attribute | Meaning |
---|---|
yaw , pitch |
components of a spherical direction vector |
min_saturation |
minimum saturation percent |
min_lightness |
minimum lightness percent |
Where the min_*
attributes are to be given as decimals in the range 0
to 1
.
The demo folder contains example code. You can view the code either by cloning this whole repository with
git clone https://github.com/joeiddon/zengine.git
or just use the GitHub web app.
To actually view each example, host locally, or view in GitHub Pages here.
Some bugs that need fixing, but I haven't got around to:
- Proper face ordering - currently done by distance to face centroids; should be done by casting a ray through the two faces. Or could use a more low level canvas rendering context, like WebGL, in order to implement a simple z-buffer.
- Rotation around the x-axis is not right-hand for some reason - probably a dodgy rotation matrix calculation. Can't easily be flipped as now lots of code relies on it being wrong! Ha!
These are some applications of this library:
If you would like to read about these projects more, I have posts on each of them here on my website.