Argument of render_3d. Positions are vec3 values in world coordinates —
camera offset is handled for you.
| Function | What it does |
|---|---|
camera() |
Camera position as vec3 |
camera_rotation() |
Camera yaw, pitch in degrees |
camera_forward() |
View direction as a unit vec3 |
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 width |
tracer(pos, color[, width[, through_walls]]) |
Line from crosshair (screen center) to a world point |
begin(mode[, width[, through_walls]]) / vertex(pos[, color]) / finish() |
Arbitrary mesh |
begin_layer(layer) / uv(u, v) |
Mesh through a custom gfx pipeline |
push() / pop() |
Matrix transform scope — coordinates become local |
origin(pos) |
Moves local origin to a world position |
translate(offset) / rotate(deg[, axis]) / scale(sx[, sy, sz]) |
Local transforms (rotate axis defaults to Y) |
rotate_camera() |
Turns the local frame to face the camera (billboard) |
through_walls = true makes the 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)Meshes
Modes: "lines", "line_strip", "quads", "triangles", "triangle_strip",
"triangle_fan", "points". ("quads" and "triangle_fan" are 3D-only — not on the
2D canvas.) Vertex color sticks until changed; width is line width / point size:
render.begin("quads", nil, true) -- mode, default width, through_walls
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 a custom GLSL shader instead of built-in shading, use begin_layer(layer) — see
Custom pipelines.
Transforms
Inside push/pop, all draw coordinates are local to the transform.
origin places the local origin at a world position (usual first call after push).
rotate_camera faces the camera with the exact orientation quaternion — no trigonometry:
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)rotate(degrees[, axis]) spins around a vec3 axis (Y by default).
scale and translate work in the local frame. Transforms nest; anything left
unbalanced is popped automatically after the callback.