Skip to content

joeiddon/zengine

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

68 Commits
 
 
 
 
 
 

Repository files navigation

zengine.js

A JavaScript 3D Rendering Engine

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!


Installation

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>

Usage

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 and z-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.


Examples

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.


Known Bugs

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!

Uses

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.