Render3D

LittleJS 3D Rendering Plugin

  • Adds a 3D scene that draws into the same WebGL canvas as the 2D game
  • Call new Render3DPlugin() in gameInit, then move render3D.camera and make EngineObject3D objects
  • EngineObject3D is an EngineObject with a 3D position, rotation and mesh
  • The 3D scene draws under the 2D sprites, so HUD and text land on top
  • Lighting is one directional light plus ambient, with optional extra lights, fog and shadows
  • Build shapes with buildBox, buildSphere and friends, or load a model with loadOBJ
  • Requires the Math3D plugin

Classes

Camera3D
CameraControl3D
EngineObject3D
HeightMap
Light3D
Mesh
ParticleEmitter3D
Render3DPlugin
Trail3D

Members

(static) render3D :Render3DPlugin

Global Render3D plugin object

Type:
  • Render3DPlugin

Methods

(static) buildBox(sizeopt) → {Mesh}

Build a box centered on the origin, six flat faces with uvs covering each face

Parameters:
NameTypeAttributesDefaultDescription
sizeVector3 | number<optional>
1

Full size, a number for a cube

Returns:
Type: 
Mesh

(static) buildCapsule(sizeopt, heightopt, sidesopt, ringsopt, smoothopt) → {Mesh}

Build a capsule standing on the Y axis, centered on the origin: a cylinder with a half sphere on each end

Parameters:
NameTypeAttributesDefaultDescription
sizenumber<optional>
1

Diameter

heightnumber<optional>
1

Total height including the rounded ends, at least the size

sidesnumber<optional>
16

Around

ringsnumber<optional>
4

On each end

smoothboolean<optional>

Defaults to render3D.smoothShading

Returns:
Type: 
Mesh

(static) buildCone(sizeopt, heightopt, sidesopt, smoothopt, cappedopt) → {Mesh}

Build a cone standing on the Y axis, centered on the origin, the point up

Parameters:
NameTypeAttributesDefaultDescription
sizenumber<optional>
1

Diameter of the base

heightnumber<optional>
1
sidesnumber<optional>
16

Around

smoothboolean<optional>

Defaults to render3D.smoothShading

cappedboolean<optional>
true

Close the base

Returns:
Type: 
Mesh

(static) buildCylinder(sizeopt, heightopt, sidesopt, smoothopt, cappedopt) → {Mesh}

Build a cylinder standing on the Y axis, centered on the origin

Parameters:
NameTypeAttributesDefaultDescription
sizenumber<optional>
1

Diameter

heightnumber<optional>
1
sidesnumber<optional>
16

Around

smoothboolean<optional>

Defaults to render3D.smoothShading

cappedboolean<optional>
true

Close the ends

Returns:
Type: 
Mesh

(static) buildExtrude(pixels, sizeopt, depthopt) → {Mesh}

Turn a sprite into a 3D block model by giving its pixels thickness

  • A pixel counts as solid when it is more than half opaque
  • Each pixel keeps its own color, so white art takes the object's tint
  • Runs of matching pixels merge into one face, and side walls appear only at the sprite's edges
  • A texture's pixels are read once and kept, so redrawing a canvas texture will not change what this builds
  • Pixels can also be an array of rows, each a Color, a truthy value for white, or a falsy value for empty
Parameters:
NameTypeAttributesDefaultDescription
pixelsTileInfo | Array.<Array.<(Color|number|boolean)>>

A tile from a loaded texture, or rows of pixels, each a Color (empty when see through), a truthy value for white or a falsy value for empty

sizeVector2<optional>

World width and height of the whole tile, centered like buildBox

depthnumber<optional>
1

Thickness along Z

Returns:
Type: 
Mesh
Example
new EngineObject3D(vec3(), buildExtrude(tile(3, 16), vec2(2), .5)); // a chunky version of tile 3

(static) buildGrid(sizeopt, segmentsopt, coloropt, heightFunctionopt, smoothopt) → {Mesh}

Build a heightfield grid in the XZ plane centered on the origin

  • smooth rounds the lighting across cells and colors each corner
  • flat lights and colors each cell on its own, so a checkerboard stays crisp
Parameters:
NameTypeAttributesDefaultDescription
sizeVector2<optional>

World size along X and Z

segmentsVector2 | number<optional>
1

Cells along X and Z, a number for both

colorColor | function<optional>

One Color for the whole grid, or (x, z) => Color

heightFunctionfunction<optional>

(x, z) => y, default flat

smoothboolean<optional>

Defaults to render3D.smoothShading

Returns:
Type: 
Mesh
Example
const ground = buildGrid(vec2(20), 10, (x, z)=> (floor(x / 2) + floor(z / 2)) & 1 ? GRAY : WHITE); // 2 unit checks

(static) buildLathe(profile, sidesopt, smoothopt, cappedopt) → {Mesh}

Spin a flat outline around the Y axis to make a round shape, like a vase or a wheel

  • profile is [[radius, y], ...] from bottom to top
  • A profile that ends where it starts makes a closed ring like a donut
Parameters:
NameTypeAttributesDefaultDescription
profileArray.<Array.<number>>
sidesnumber<optional>
16

Around the axis

smoothboolean<optional>

Defaults to render3D.smoothShading

cappedboolean<optional>
true

Close the ends that have a radius with flat discs

Returns:
Type: 
Mesh
Example
const vase = buildLathe([[0, -1], [.8, -.3], [.9, .2], [.4, .6], [0, 1]], 12);

(static) buildLoft(stations) → {Mesh}

Build a hull from a row of diamond shaped slices along Z, for ships, planes and cars

  • Each slice is [z, width, top, bottom, sideHeight]
  • sideHeight is 0 to 1 and puts the side corners between the bottom and the top
  • List the slices nose first, with the nose at the largest z
Parameters:
NameTypeDescription
stationsArray.<Array.<number>>
Returns:
Type: 
Mesh
Example
const hull = buildLoft([[1.2, .4, .2, -.1], [0, 1.4, .5, -.4], [-1, 1, .3, -.3]]);

(static) buildRibbon(points, widthopt, coloropt, closedopt, upopt) → {Mesh}

Build a lit ribbon along a path, for roads, tracks and walls

  • Each segment is a flat quad, the sides are across the path in the plane of the up vector
Parameters:
NameTypeAttributesDefaultDescription
pointsArray.<Vector3>

Center line in order

widthnumber | Array.<number><optional>
1

Full width, one for all or one per point

colorColor | Array.<Color><optional>

One for all or one per point

closedboolean<optional>
false

Join the last point back to the first

upVector3<optional>

Which way the ribbon faces

Returns:
Type: 
Mesh
Example
const road = buildRibbon(trackPoints, 8, GRAY, true); // a loop of road

(static) buildSky(topColoropt, horizonColoropt, bottomColoropt, sidesopt, ringsopt) → {Mesh}

Build a sky dome: a sphere colored by direction, wound to be seen from inside

  • set it as render3D.sky and the pass draws it around the camera behind everything
Parameters:
NameTypeAttributesDefaultDescription
topColorColor<optional>

Straight up

horizonColorColor<optional>

Level with the camera

bottomColorColor<optional>

Straight down, what a camera looking at the ground sees past its edge; defaults to the horizon color

sidesnumber<optional>
16

Around

ringsnumber<optional>
8

Top to bottom

Returns:
Type: 
Mesh

(static) buildSphere(sizeopt, sidesopt, ringsopt, smoothopt) → {Mesh}

Build a sphere centered on the origin

Parameters:
NameTypeAttributesDefaultDescription
sizenumber<optional>
1

Diameter

sidesnumber<optional>
16

Around

ringsnumber<optional>
8

Top to bottom

smoothboolean<optional>

Defaults to render3D.smoothShading

Returns:
Type: 
Mesh

(static) buildText3D(text, sizeopt, depthopt, fontopt) → {Mesh}

Build a mesh of extruded text from an image font, the engine font by default so it needs no assets

  • Each glyph is extruded once per font and reused, the block is centered and faces +Z
  • Newlines stack downward, spaced a little wider than the character height so the sides do not collide
  • Every call builds a new mesh, dispose the old one when text changes often
  • Glyphs are white in the engine font, so the object's color tints the text
Parameters:
NameTypeAttributesDefaultDescription
textstring | number
sizenumber<optional>
1

Character height in world units

depthnumber<optional>
0.2

Thickness along Z

fontImageFont<optional>

Defaults to engineImageFont

Returns:
Type: 
Mesh
Example
new EngineObject3D(vec3(0, 2, 0), buildText3D('HELLO'), undefined, YELLOW);

(static) buildTorus(sizeopt, tubeSizeopt, sidesopt, tubeSidesopt, smoothopt) → {Mesh}

Build a donut lying flat around the Y axis

Parameters:
NameTypeAttributesDefaultDescription
sizenumber<optional>
1

Diameter of the whole donut, outside edge to outside edge

tubeSizenumber<optional>
0.3

Diameter of the tube

sidesnumber<optional>
16

Around the ring

tubeSidesnumber<optional>
8

Around the tube

smoothboolean<optional>

Defaults to render3D.smoothShading

Returns:
Type: 
Mesh

(static) debugBox3D(pos, sizeopt, coloropt, timeopt, rotationopt)

Draw a debug wireframe box

Parameters:
NameTypeAttributesDefaultDescription
posVector3

Center

sizeVector3 | number<optional>
1

Full size, a number for a cube

colorColor<optional>
timenumber<optional>
0

How long to show it, 0 is one frame

rotationVector3<optional>

vec3(pitch, yaw, roll)

(static) debugLine3D(posA, posB, coloropt, widthopt, timeopt)

Draw a debug line

Parameters:
NameTypeAttributesDefaultDescription
posAVector3
posBVector3
colorColor<optional>
widthnumber<optional>
timenumber<optional>
0

How long to show it, 0 is one frame

(static) debugPoint3D(pos, coloropt, timeopt, sizeopt)

Draw a debug point as a small cross of three lines

Parameters:
NameTypeAttributesDefaultDescription
posVector3
colorColor<optional>
timenumber<optional>
0

How long to show it, 0 is one frame

sizenumber<optional>
0.2

Length of the cross

(static) debugSphere3D(pos, sizeopt, coloropt, timeopt)

Draw a debug wireframe sphere as three rings

Parameters:
NameTypeAttributesDefaultDescription
posVector3

Center

sizenumber<optional>
1

Diameter

colorColor<optional>
timenumber<optional>
0

How long to show it, 0 is one frame

(static) engineObjectsCallback3D(pos, size, callback, objectsopt)

Call a function for each EngineObject3D whose box overlaps a box

Parameters:
NameTypeAttributesDescription
posVector3

Center of the box

sizeVector3 | number

Full size of the box, a number for a cube

callbackfunction
objectsArray.<EngineObject><optional>

Defaults to every object

(static) engineObjectsCollect3D(pos, size, objectsopt) → {Array.<EngineObject3D>}

Collect the EngineObject3D objects whose boxes overlap a box, sizes are full sizes

  • Boxes are axis aligned around the world position, rotation3D is ignored; lights, emitters and trails have no size
Parameters:
NameTypeAttributesDescription
posVector3

Center of the box

sizeVector3 | number

Full size of the box, a number for a cube

objectsArray.<EngineObject><optional>

Defaults to every object

Returns:
Type: 
Array.<EngineObject3D>

(static) engineObjectsRaycast3D(ray, objectsopt) → {Array.<EngineObject3D>}

Collect every EngineObject3D a ray passes through, nearest first, the 3D twin of engineObjectsRaycast

  • The ray has no end, so everything along it counts however far away it is
  • Use render3D.pick for the nearest one on its own, with the distance to it
Parameters:
NameTypeAttributesDescription
rayRay3D

From render3D.screenToRay, or any ray

objectsArray.<EngineObject><optional>

Defaults to every object; only those with a mesh or a sprite count

Returns:
Type: 
Array.<EngineObject3D>

(async, static) loadOBJ(url, smoothopt) → {Promise.<Mesh>}

Fetch and parse an OBJ file

Parameters:
NameTypeAttributesDescription
urlstring
smoothboolean<optional>

Compute smooth normals when the file has none, defaults to render3D.smoothShading

Returns:
Type: 
Promise.<Mesh>
Example
const mesh = await loadOBJ('ship.obj'); // in an async gameInit

(static) parseOBJ(text, smoothopt) → {Mesh}

Parse Wavefront OBJ text into a Mesh

  • Reads v, vt, vn and f lines with convex polygons of any size, materials and groups are ignored
  • Normals come from the file when every corner of a face has one, otherwise from the face
  • Use mesh.center() and mesh.fit(size) to bring a model of unknown units to the origin
Parameters:
NameTypeAttributesDescription
textstring
smoothboolean<optional>

Compute smooth normals when the file has none, defaults to render3D.smoothShading

Returns:
Type: 
Mesh
Example
new EngineObject3D(vec3(), parseOBJ(objText).center().fit(4));