LittleJS 1.30.0

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 the sun plus ambient, with optional extra lights, fog and shadows
  • Any object or draw can bring its own Shader, a mainImage snippet the lighting then applies to, and a mainNormal in it bends the normal the lighting uses
  • Meshes and the basic builders are in render3dMesh.js, EngineObject3D, instancing and lights in render3dObject.js, both right after this one; the other builders, terrain, particles, camera controls and the OBJ loader are in the Render3D Extras plugin, which goes after those
  • Requires the Math3D plugin

Classes

Functions

Members

Constants

Typedefs

Functions

buildBox(size, bevel, bevelSegments) → Meshrender3dMesh.js:1139

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

  • bevel cuts its edges and corners: 1 segment is a flat chamfer, more round them, and the biggest bevel, half the smallest side, rounds a cube into a ball
size Vector3|number optional, default 1

Full size, a number for a cube

bevel number optional, default 0

Size of the cut on each edge, clamped to half the smallest side

bevelSegments number optional, default 1

Steps around each edge, 1 for a flat chamfer

buildCapsule(size, height, sides, rings, smooth) → Meshrender3dExtras.js:176

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

size number optional, default 1

Diameter

height number optional, default 1

Total height including the rounded ends, at least the size

sides number optional, default 16

Around

rings number optional, default 4

On each end

smooth boolean optional

Defaults to render3D.smoothShading

buildCone(size, height, sides, smooth, capped, bevel, bevelSegments) → Meshrender3dExtras.js:155

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

size number optional, default 1

Diameter of the base

height number optional, default 1
sides number optional, default 16

Around

smooth boolean optional

Defaults to render3D.smoothShading

capped boolean optional, default true

Close the base

bevel number optional, default 0

Size of the cut on the base rim, clamped to the radius and half the slanted side

bevelSegments number optional, default 1

Steps around the rim, 1 for a flat chamfer

buildCylinder(size, height, sides, smooth, capped, bevel, bevelSegments) → Meshrender3dExtras.js:133

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

size number optional, default 1

Diameter

height number optional, default 1
sides number optional, default 16

Around

smooth boolean optional

Defaults to render3D.smoothShading

capped boolean optional, default true

Close the ends

bevel number optional, default 0

Size of the cut on the top and bottom rims, clamped to the radius and half the height

bevelSegments number optional, default 1

Steps around each rim, 1 for a flat chamfer

buildExtrude(pixels, size, depth) → Meshrender3dExtras.js:305

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
pixels TileInfo|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

size Vector2 optional

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

depth number optional, default 1

Thickness along Z

new EngineObject3D(vec3(), buildExtrude(tile(3, 16), vec2(2), .5)); // a chunky version of tile 3
buildGrid(size, segments, color, heightFunction, smooth) → Meshrender3dMesh.js:1182

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
  • doubleSided, a sheet seen from both sides; turn it off for ground only ever seen from above
  • One cell is a plain square, render3D.planeMesh and planeMeshDoubleSided are shared ones
size Vector2|number optional

World size along X and Z, a number for a square

segments Vector2|number optional, default 1

Cells along X and Z, a number for both

color Color|function optional

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

heightFunction function optional

(x, z) => y, default flat

smooth boolean optional

Defaults to render3D.smoothShading with a heightFunction; a flat grid is flat shaded, since its light is even anyway and smoothing would only blend its cell colors; pass smooth to blend a gradient

const ground = buildGrid(vec2(20), 10, (x, z)=> (floor(x / 2) + floor(z / 2)) & 1 ? GRAY : WHITE); // 2 unit checks
buildLathe(profile, sides, smooth, capped) → Meshrender3dMesh.js:926

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
  • An end left open, with a radius and no cap, makes the mesh doubleSided so its inside shows
  • An end on the axis smooth shades as a round pole like a sphere's when its segment is within 45 degrees of level, and as a point like a cone's tip when it is steeper
profile Array<Array<number>>
sides number optional, default 16

Around the axis

smooth boolean optional

Defaults to render3D.smoothShading

capped boolean optional, default true

Close the ends that have a radius with flat discs

const vase = buildLathe([[0, -1], [.8, -.3], [.9, .2], [.4, .6], [0, 1]], 12);
buildLoft(stations) → Meshrender3dExtras.js:267

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
stations Array<Array<number>>
const hull = buildLoft([[1.2, .4, .2, -.1], [0, 1.4, .5, -.4], [-1, 1, .3, -.3]]);
buildLoft.section()render3dExtras.js:275
buildRibbon(points, width, color, closed, up) → Meshrender3dExtras.js:230

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
  • doubleSided, so it is seen and lit from below as well
points Array<Vector3>

Center line in order

width number|Array<number> optional, default 1

Full width, one for all or one per point

color Color|Array<Color> optional

One for all or one per point

closed boolean optional, default false

Join the last point back to the first

up Vector3 optional

Which way the ribbon faces

const road = buildRibbon(trackPoints, 8, GRAY, true); // a loop of road
buildSky(topColor, horizonColor, bottomColor, sides, rings) → Meshrender3dMesh.js:1268

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
topColor Color optional

Straight up

horizonColor Color optional

Level with the camera

bottomColor Color optional

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

sides number optional, default 16

Around

rings number optional, default 8

Top to bottom

buildSphere(size, sides, rings, smooth) → Meshrender3dMesh.js:1041

Build a sphere centered on the origin

size number optional, default 1

Diameter

sides number optional, default 16

Around

rings number optional, default 8

Top to bottom

smooth boolean optional

Defaults to render3D.smoothShading

buildText3D(text, size, depth, font) → Meshrender3dExtras.js:401

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
text string|number
size number optional, default 1

Character height in world units

depth number optional, default 0.2

Thickness along Z

font ImageFont optional

Defaults to engineImageFont

new EngineObject3D(vec3(0, 2, 0), buildText3D('HELLO'), undefined, YELLOW);
buildTorus(size, tubeSize, sides, tubeSides, smooth) → Meshrender3dExtras.js:204

Build a donut lying flat around the Y axis

size number optional, default 1

Diameter of the whole donut, outside edge to outside edge

tubeSize number optional, default 0.3

Diameter of the tube

sides number optional, default 16

Around the ring

tubeSides number optional, default 8

Around the tube

smooth boolean optional

Defaults to render3D.smoothShading

debugBox3D(pos, size, color, time, rotation)render3dDebug.js:45

Draw a debug wireframe box

pos Vector3

Center

size Vector3|number optional, default 1

Full size, a number for a cube

color Color optional
time number optional, default 0

How long to show it, 0 is one frame

rotation Vector3 optional

vec3(pitch, yaw, roll)

debugLine3D(posA, posB, color, width, time)render3dDebug.js:87

Draw a debug line

posA Vector3
posB Vector3
color Color optional
width number optional
time number optional, default 0

How long to show it, 0 is one frame

debugPoint3D(pos, color, time, size)render3dDebug.js:99

Draw a debug point as a small cross of three lines

pos Vector3
color Color optional
time number optional, default 0

How long to show it, 0 is one frame

size number optional, default 0.2

Length of the cross

debugSphere3D(pos, size, color, time)render3dDebug.js:64

Draw a debug wireframe sphere as three rings

pos Vector3

Center

size number optional, default 1

Diameter

color Color optional
time number optional, default 0

How long to show it, 0 is one frame

engineObjectsCallback3D(pos, size, callback, objects, testCenters)render3dObject.js:1237

Call a function for each EngineObject3D whose box overlaps a sphere or a box

  • An object destroyed by an earlier callback is skipped
pos Vector3

Center of the area

size Vector3|number

Diameter of a sphere if a number, 0 for a point, full size of a box if a Vector3

callback function
objects Array<EngineObject> optional

Defaults to every object

testCenters boolean optional, default false

Test only each object's center, see engineObjectsCollect3D

engineObjectsCollect3D(pos, size, objects, testCenters) → Array<EngineObject3D>render3dObject.js:1043

Collect the EngineObject3D objects whose boxes overlap a sphere or a box, the 3D twin of engineObjectsCollect

  • Each object is its size3D box at its world position, turned as it is turned; lights, emitters and trails have no size and are never collected
pos Vector3

Center of the area

size Vector3|number

Diameter of a sphere if a number, 0 for a point, full size of a box if a Vector3

objects Array<EngineObject> optional

Defaults to every object

testCenters boolean optional, default false

Test only each object's center, a little faster, and ignores object sizes

engineObjectsRaycast3D(ray, objects) → Array<EngineObject3D>render3dObject.js:1215

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
ray Ray3D

From render3D.screenToRay, or any ray

objects Array<EngineObject> optional

Defaults to every object; only those with a mesh or a sprite count, and the height maps, voxel maps and mesh colliders, on their surfaces

loadCubeMap(sources) → Promise<CubeMap>asyncrender3d.js:2328

Load a cube map from six square images of one size

  • The images are a sky box set as three.js's CubeTextureLoader takes them, and show the same: each face seen from inside as its image is drawn
sources Array<string>

The images of +x, -x, +y, -y, +z and -z, as a sky box set names them right, left, top, bottom, front and back

loadOBJ(url, smooth) → Promise<Mesh>asyncrender3dExtras.js:2738

Fetch and parse an OBJ file

url string
smooth boolean optional

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

const mesh = await loadOBJ('ship.obj'); // in an async gameInit
makeCubeMap(size, colorOf) → CubeMaprender3d.js:2298

Make a cube map by asking a function the color of each direction

  • The function gets a unit Vector3 for each pixel of each face and gives a Color
  • It runs size * size * 6 times, so a size of 64 or 128 makes one at once, larger takes a moment
size number

Pixels a side of each face

colorOf function

The color seen looking that way

// a sky, blue above and pale at the horizon, with a sun
const sun = vec3(1, 1, -1).normalize();
render3D.environment = makeCubeMap(64, (d)=> hsl(.6, .7, .9 - max(d.y, 0) * .5).lerp(WHITE, max(0, d.dot(sun)) ** 64));
meshWriteVertex(floats, ints, j, x, y, z, nx, ny, nz, u, v, rgba)render3dMesh.js:48

Write one vertex in the GPU layout, RENDER3D_VERTEX_FLOATS floats, for vertex data given to mesh.setVertexData: its place, its normal, its uv and its color as RGBA bytes, in numbers so a loop over many makes no objects

floats Float32Array

The vertex data

ints Uint32Array

A view of the same buffer, for the color

j number

The vertex's first float, its number times RENDER3D_VERTEX_FLOATS

x number
y number
z number
nx number

The normal, unit length

ny number
nz number
u number

Across the tile, 0 to 1

v number

Down the tile, 0 to 1

rgba number

The color as color.rgbaInt() gives it

normalMapFromHeight(size, heightFunction, strength) → TextureInforender3dExtras.js:50

Make a normal map from a height at each pixel, for bumps and grooves with no image file: the slope at each pixel from its neighbors' heights, taken around the edges so the map tiles; set it as an object's normalMap

size Vector2

In pixels

heightFunction function

The height 0 to 1 at a pixel, x across and y down

strength number optional, default 1

How steep the slopes are: a height change of 1 over one pixel leans the normal by strength

Returns
  • Wraps; headless it has no image
parseOBJ(text, smooth) → Meshrender3dExtras.js:2660

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
  • Back faces are skipped like any mesh, set doubleSided for a model with open walls or single sided parts
text string
smooth boolean optional

Compute smooth normals for the faces the file gives none, defaults to render3D.smoothShading

new EngineObject3D(vec3(), parseOBJ(objText).center().fit(4));

Members

Global Render3D plugin object

Constants

RENDER3D_VERTEX_FLOATS : number default 9render3d.js:33

Floats in each vertex of the GPU layout: position xyz, normal xyz, uv, and the color as rgba bytes in the last one, what meshWriteVertex writes and mesh.setVertexData takes

Typedefs

LensFlareElement : Objectrender3dExtras.js:2352

A part of a lens flare

at number

Where along the line: 0 the sun, 1 the middle of the screen, 2 as far past it

size number|Vector2

How big across, as a part of the screen's height, a vector for a part wider than it is tall

color Color

Its color, the alpha how bright

shape 'glow'|'disc'|'ring'|'hex'|'streak'|'star' optional

A glow when left out

tileInfo TileInfo optional

A tile of the game's own to draw in place of a shape, best white on clear

angle number optional

How far it is turned, in radians

Particle3D : Objectrender3dExtras.js:1669

A particle as a ParticleEmitter3D's callbacks see it: one object the emitter reuses, set from the particle for each call and written back after it, so copy what you keep

emitter ParticleEmitter3D

The emitter it is in

pos Vector3

Where it is, change it to move it

velocity Vector3

How far it moves each frame

age number

Seconds it has lived

lifeTime number

Seconds it lives

scale number

How much the emitter grows its effect, from its scale3D and its parents', as the 2D particle's scale

destroyed boolean

Set by destroy

destroy function

End it this update, the destroy callback gets it

Particle3DCallback(particle) → voidrender3dExtras.js:1685
particle Particle3D
Particle3DCollideCallback(particle, level, pos) → boolean|voidrender3dExtras.js:1692
particle Particle3D
level EngineObject3D

The HeightMap, VoxelMap or MeshCollider it hit

pos Vector3

Where it hit

Returns
  • true to stop it there; a callback that returns nothing lets it pass through
Render3DDrawState : Objectrender3d.js:108

The draw state's values, behind render3D's accessors, and the rgb emissiveMapColor had when it was set

blend boolean
additive boolean
depthTest boolean
depthWrite boolean
cullBackFaces boolean
mirrored boolean
lighting boolean
emissive number
receiveShadow boolean
specular number
pixelated boolean
shader Shader|undefined
normalMap TextureInfo|undefined
normalScale number
shininess number
reflectivity number
emissiveMap TextureInfo|undefined
emissiveMapColor Color
environmentMap CubeMap|undefined
roundLighting boolean
emissiveR number
emissiveG number
emissiveB number
VoxelHit : Objectrender3dVoxels.js:37

What VoxelMap.raycast finds: how far along the ray, the block's cell and type, and the normal of the face it comes in through