Skip to content

3D renderer

Lines, boxes, tracers, billboard text and meshes drawn in world space.

The argument of render_3d. Positions are vec3 values in world coordinates; the camera offset is handled for you. through_walls = true makes a shape visible through blocks.

module:event("render_3d", function(render)
    for _, p in ipairs(world:players()) do
        if not p:is_self() then
            local pos = p:position()
            local half = p:width() / 2
            render.box(pos + vec3(-half, 0, -half),
                       pos + vec3(half, p:height(), half),
                       0xFF4FF2A6, 2)
            render.text(p:name(), pos + vec3(0, p:height() + 0.4, 0), 0xFFFFFFFF, 1, true)
        end
    end
end)
Function Draws
line(from, to, color[, width[, through_walls]]) Line between two world points
box(min, max, color[, width[, through_walls]]) Box outline
filled_box(min, max, color[, through_walls]) Solid translucent box, all six faces
quad(a, b, c, d, color[, through_walls]) Filled quad
triangle(a, b, c, color[, through_walls]) Filled triangle
point(pos, color[, size[, through_walls]]) Point sprite, size in pixels, default 4
text(str, pos[, color[, scale[, through_walls[, background]]]]) Camera-facing billboard text, returns its width
tracer(pos, color[, width[, through_walls]]) Line from the crosshair to a world point
Function Returns
camera() Camera position as vec3
camera_rotation() Camera yaw, pitch in degrees
camera_forward() View direction as a unit vec3

Meshes

begin(mode[, width[, through_walls]]), vertex(pos[, color]) and finish() build an arbitrary mesh. Modes are "lines", "line_strip", "quads", "triangles", "triangle_strip", "triangle_fan" and "points"; "quads" and "triangle_fan" exist only here, not on the 2D canvas. A vertex color holds until you change it, and width is the line width or point size.

render.begin("quads", nil, true)
render.vertex(pos, 0x604FF2A6)
render.vertex(pos + vec3(1, 0, 0))
render.vertex(pos + vec3(1, 0, 1))
render.vertex(pos + vec3(0, 0, 1))
render.finish()

For your own GLSL instead of the built-in shading, open the mesh with begin_layer(layer) and set texture coordinates with uv(u, v). See Custom pipelines.

Transforms

Function Does
push(), pop() Opens and closes a transform scope, inside which coordinates are local
origin(pos) Moves the local origin to a world position
translate(offset) Shifts the local frame
rotate(deg[, axis]) Rotates around a vec3 axis, Y by default
scale(sx[, sy, sz]) Scales the local frame
rotate_camera() Turns the local frame to face the camera, using the orientation quaternion, so no trigonometry

origin is the usual first call after push. Transforms nest, and anything left unbalanced is popped after the callback.

module:event("render_3d", function(render)
    for _, p in ipairs(world:players()) do
        if not p:is_self() then
            render.push()
            render.origin(p:position() + vec3(0, p:height() / 2, 0))
            render.rotate_camera()
            render.begin("quads")
            render.vertex(vec3(-0.6, 0.6, 0), 0x904FF2A6)
            render.vertex(vec3(0.6, 0.6, 0))
            render.vertex(vec3(0.6, -0.6, 0))
            render.vertex(vec3(-0.6, -0.6, 0))
            render.finish()
            render.pop()
        end
    end
end)
Navigation

Type to search…

↑↓ navigate↵ selectEsc close