Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit95280a384c

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 public image_url, or a local image VFS 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 the asset its completed generate / from_image row names (the .bundle) or by the asset_path that run was directed to write (/zero/source/game/art/x.glb). The run stamped the provider's id for the mesh on that asset, and rig sends it. A mesh this service did not generate carries no such id, and rig refuses it before anything is charged, naming the other two forms.
    • task_id: the provider's id for the mesh, the outputs.task_id of 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.

InputWhat it decidesDefault
enable_pbrMetallic / roughness / normal maps beside the base colour, so the surface answers the world's lighting instead of rendering as flat painted colour.true
texture_resolution2k, 4k, 8k. 4k costs the same credits as 2k; each map is four times the size.2k
ai_modelWhich generation model runs: meshy-7.1, meshy-7, meshy-6, meshy-6-lite, or latest to track the newest.the provider's
ultra_modeThe provider's high-fidelity path: more geometry detail, cleaner silhouette.off
target_polycountRetopologise to about this many polygons (100–300000).30000, 50000 on generate_rigged
topologytriangle or quad, chosen during retopology.the provider's
should_remeshRetopology on or off. false keeps the provider's raw density.on
should_texturefrom_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.