Builtin Library
README.md
mesh_gen
Generate a 3D mesh (a textured .glb) from a text prompt or a reference image.
Reach for this when you need a 3D model — a prop, a piece of furniture, a
creature — and you only have a description or a picture of it.
Operations
generate({ prompt, … })— text-to-3D. Runs a preview pass then a refine pass, downloads the resulting GLB, and writes it under/zero/source/generated/meshes/. Returns a generation handle; the mesh is ready when the handle completes.from_image({ image_url? | image?, … })— image-to-3D. A textured GLB from a reference image: a publicimage_url, or a localimageVFS path sent as a data URI.rig({ asset? | task_id? | model_url?, height_meters? }): auto-rig a mesh into an animatable, skinned character. Name the mesh in one of three ways, and the result is a rigged GLB ready to drive with any clip. Height defaults to 1.7 m.asset: a mesh this service generated, by theassetits completedgenerate/from_imagerow names (the.bundle) or by theasset_paththat run was directed to write (/zero/source/game/art/x.glb). The run stamped the provider's id for the mesh on that asset, andrigsends it. A mesh this service did not generate carries no such id, andrigrefuses it before anything is charged, naming the other two forms.task_id: the provider's id for the mesh, theoutputs.task_idof the job that generated it.model_url: a public URL of a mesh file, for a mesh from anywhere else.
generate_rigged({ prompt, … })— text-to-character: generate and rig in one run. The mesh it generates is retopologised to about 50000 polygons before the rigging pass reads it; that pass takes a mesh of at most 320,000 faces.
Quality
Results arrive game-ready: PBR-textured at 2k and retopologised to
about 30000 polygons (50000 for generate_rigged). A scene can hold many
of them. The provider's raw output is several hundred thousand to a few million
triangles with 4k maps, and one 4k map is 85 MB once the engine holds it, so the
denser and sharper results are what you ask for when an asset is seen up close.
:operations() lists every control with the values it accepts and the default
it carries.
| Input | What it decides | Default |
|---|---|---|
enable_pbr | Metallic / roughness / normal maps beside the base colour, so the surface answers the world's lighting instead of rendering as flat painted colour. | true |
texture_resolution | 2k, 4k, 8k. 4k costs the same credits as 2k; each map is four times the size. | 2k |
ai_model | Which generation model runs: meshy-7.1, meshy-7, meshy-6, meshy-6-lite, or latest to track the newest. | the provider's |
ultra_mode | The provider's high-fidelity path: more geometry detail, cleaner silhouette. | off |
target_polycount | Retopologise to about this many polygons (100–300000). | 30000, 50000 on generate_rigged |
topology | triangle or quad, chosen during retopology. | the provider's |
should_remesh | Retopology on or off. false keeps the provider's raw density. | on |
should_texture | from_image only — false returns bare geometry for a material of your own. | true |
target_polycount is the budget knob. A lower figure buys a lighter mesh
and pays for it in softer detail; a higher one keeps more of the form, up to
300000. should_remesh = false skips retopology and returns the provider's raw
density, the most detail the run produced, at several hundred thousand
triangles or more.
generate_rigged defaults to 50000 polygons. It ends in a rigging pass that
takes a mesh of at most 320,000 faces, so every figure in the span can be
rigged; should_remesh = false on it sends the raw density to that pass, which
often exceeds the limit.
A value outside what an input accepts is refused before anything is charged, so
a mistyped 4K costs a message rather than a preview pass. A target_polycount
outside 100–300000 is refused the same way, and :operations() publishes the
span as min / max on the input.
local mesh = asset.resolve("mesh_gen", "service")
-- Nothing to ask for: a game-ready prop, PBR at 2k, about 30000 polygons.
local chest = mesh:invoke({ prompt = "a wooden treasure chest, iron banding, weathered oak" })
-- Spend more only where it is seen close up.
local hero = mesh:invoke({
prompt = "a hero's greatsword",
texture_resolution = "4k",
target_polycount = 120000,
ultra_mode = true,
})
print(chest.id, hero.id)
Using it
local mesh = asset.resolve("mesh_gen", "service")
print(mesh:cost(), mesh:balance()) -- budget before spending
local g = mesh:invoke({ prompt = "a wooden treasure chest" })
-- Generation takes a couple of minutes. Watch the run until it settles; a
-- completed row's `asset` is the finished, spawnable `.bundle`.
local row = tools.use("services", "status", { id = g.id })
while row ~= nil and row.status ~= "completed" and row.status ~= "failed" do
task.wait(5)
row = tools.use("services", "status", { id = g.id })
end
print(row.status, row.asset)
The handle's asset_path is where the run directs the raw generated file; the
asset it becomes is the completed status row's asset, which is what to spawn.
Cost
:cost() is what a run spends when it names none of the options that cost extra
— 10 credits for generate (a preview call and a refine call), 5 for
from_image and rig, 15 for generate_rigged. Only texture_resolution = "8k" and ultra_mode = true cost above that; enable_pbr and 4k are free,
and should_texture = false on from_image costs less. Check :balance()
first.