Tier 2 · Art and 3D asset production
AI 3D model generation
Generate game 3D assets from images with measured proportions.
Generate game 3D assets from images with measured proportions.
Cross-project rules for generating game 3D assets from AI (Meshy multi-image-to-3d and kin). Project-level procedure lives in the project's own pipeline doc; these are the lessons that transfer.
- GEN-REF-NO-SHADOW-BLEED (HARD) — strip cast shadows / AO / lighting gradients from every plate before image-to-3D or retexture. The 3D stage bakes whatever lighting is in the pixels into the albedo. A cinematic lit ref becomes a dirty texture even when the mesh is right. Feed even-unlit plates (flat illumination, no ground contact dark, no rim). Also drop micro-holes/filigree the poly budget cannot hold — simplify the ref rather than hoping more tris reconstruct cutouts. (a mobile strategy game: Undead castle mesh accepted, shadows in the ref bled into paint.)
- MULTI-OBJECT-INPUT (HARD) — every image fed to an image-to-3D task must contain exactly ONE subject, and you must EYEBALL EVERY image, not just the first. The 3D stage faithfully builds everything in frame: a turnaround sheet on one canvas, two poses side by side, a prop, a second figure — each becomes a real extra object fused into the output mesh. Multi-view concept generators sometimes return one image CONTAINING several poses — crop to a single subject or reject before spending on 3D. (a mobile strategy game air-unit batch; required after duplicate-object outputs.)
- SKELETON-FIT-LANDMARKS (HARD) — "A-pose" in a prompt is not a bind contract. If generated
bodies must wear a licensed pack skeleton, encode measured joint fractions of the pack's
visual mesh height (pelvis / shoulder / fist height and fist |x|), and scale the copied
armature by
new_mesh_h / pack_visual_h, nevernew_mesh_h / armature_h. Bone-span is shorter than the skinned mesh (helm/boots live outside Head/Foot); filling the mesh with the bone chain overscales A-pose arms (~1.23× on a Bip001 infantry pack) and is why a "slightly larger" weapon-free body misses the fists. Gates must print a named fail class (ARMS_GLUED,STUBBY_ARM_SPAN,BONE_FILL_OVERSCALE) — a boolean limb-count OK that only catches extra arms will green-light glued-arm barrels. (a mobile strategy game: pack visual 1.595 m vs bone-span 1.293 m; 1.70 m melee is a 1.07× visual scale, not 1.32× bone-fill.) - HUMANOID-CLIPS-NOT-BLENDER-ORIGINAL (HARD) — do not play Unity Humanoid pack clips in Blender as the bind control. Rest overlay vs the pack mesh FBX at authored rest. Walk/attack/death stills come from Unity Humanoid playback. See the blender page.
- FREE-MULTIVIEW-IDENTITY (HARD) — when multi-view is not a single provider multiview task,
only
view_0is a new identity gen; every other angle is image-edit ofview_0(“exact same character, only change camera”). Three independent free gens as a “turnaround” = three different characters and poisons 3D. Prefer front · elevated three-quarter · back for RTS-like games — pure orthographic side T-pose invents extra arms. Bodies for socketed weapons: empty closed fists, no held/fused weapons on the body concept (weapon = separate asset). Copy accepted images into a durable repo work dir the same turn; free/Imagine tools rate-limit — keep parallel gens low (≈2). (a mobile strategy game free-concept / Grok Imagine.) - Reconstruction hallucinations are a separate failure class view-auditing cannot prevent: when supplied views disagree hard (long tail reads as a neck from behind; side profile shares no silhouette with the front), the solver duplicates the subject or fuses parts wrong (two-headed tail). Cap the cost: two failed 3D rolls on the same concept = STOP — change the concept pose (raised/V-folded wings, compact connected silhouette) or take the design back to the developer. Never roll a third time on identical inputs.
- Island-soup meshes take NO geometry heuristics. AI-generated meshes are hundreds of loose
shells with no solid core (largest island can be <100 verts of thousands); every automated
island pass tried — size-threshold debris cull, nearest-gap docking — false-positived en masse
and destroyed the model. Manual per-case Blender fixes or a reroll; never a heuristic. Visual
gap fixes that ARE safe: double-sided material (
_Cull 0) for single-sheet cloth/wings, and an interior occluder plug (separate object inside the cavity) for holes backed by geometry. Count shells by vertex POSITION before calling a mesh island-soup: glTF splits every UV seam, and three Meshy parts stored as 133, 423 and 3812 pieces were each ONE shell once coincident vertices were joined (the ai mesh cleanup page GLTF-SEAM-SPLIT-SHELLS,tools/blender/ai_mesh_report.py). - IP-DISTINCTIVENESS gates the 2D concept (HARD). Keeping franchise terms out of prompts does not stop generators from converging on famous archetypes (armored gryphon + knight rider = WoW's gryphon rider; orc on wyvern = wind rider). At the concept gate ask: "would a player screenshot this and name a specific franchise unit?" If yes → redesign the creature/silhouette, not the palette. Developer-caught on a mobile strategy game.
- Inspect on a flat loud background before accepting any mesh. Isolated render (dedicated layer, solid magenta clear, flat ambient, 6 views): enclosed background pixels inside the silhouette = see-through holes (flood-fill from image borders finds them mechanically); a front-culled unlit duplicate shows exposed-interior regions. Both are ASSISTS to locate what an eye reported — the developer's eye is the accept gate, because on island-soup a detector strong enough to catch everything false-positives too much to act on automatically.
- Download outputs immediately — non-Enterprise Meshy task assets expire after ~3 days, and any later re-export (mobile-tier remesh at a lower polycount, format change) needs the task id alive. Decide quality tiers and fire the cheap remesh in the SAME session as the generation.
- FREE-RETRY-FIRST — a same-input reroll rides the provider's free-retry entitlement, never a fresh paid task. Meshy plans bundle free retries on COMPLETED generations ("re-run the generation for free — no credits deducted"; Pro 4 / Premium 12 / Ultra 40 / Studio 24 / Enterprise 100 at) — but only as a WEB-WORKSPACE button: the API has no retry endpoint on non-Enterprise plans, so an API-only pipeline silently pays full price for every hallucination-class reroll (invented floaters, duplicated creature, deformed limb from a clean concept) the plan would have covered. Route: defect with unchanged inputs → workspace Retry (free) → download; a paid task only when the INPUTS change (view set, crops, regenerated concept). Generalize: before wiring any generation provider, audit its retry/refund surface — entitlements often live only in the web app and never appear in the API reference. The two-roll stop binds on free retries too: it exists for recurrence, not just cost. (a mobile strategy game: ~250 cr of demon/air same-input rerolls were paid at full API price while the plan's free retries sat unused.)
- MIRROR-AXIS-PROOF — before mirroring geometry to rebuild a missing symmetric part, PROVE the mirror axis, and expect the defect to be SMALL. AI meshes import with arbitrary axis conventions (one Tripo GLB: X = body, Y = left-right, Z = up), and a voxel/vertex mirror-asymmetry scan across the WRONG axis reads head-vs-tail as "missing half" — acting on that builds a two-headed Janus model. Two sanity gates before any mirror edit: (1) a missing wing/limb is a small unmatched cluster (~a few hundred verts) on the intact side — if ~half the mesh reads unmatched, the axis is wrong, re-scan across the other axis; (2) verify axes visually from a top-view render, never from island bbox guesswork. When copying the intact part: hand-pick its components (print candidates, eyeball before committing — per-mesh manual pick, not a banned island heuristic), and exclude anything that already HAS a twin — mirroring a twinned panel lands a coincident z-fighting double. The hole detector cannot see missing-silhouette defects: the accept evidence is a before/after render of the VIEW where the defect was reported. Always run the flat-background inspection gate on the mirrored result — it is what caught the Janus attempt (original file untouched, so the wrong mirror cost nothing). Corollary (same model, next day): per-component surgery LOSES on wing stacks — half-mirror is the default repair. Wings on AI models are layered multi-sheet fans, and a nearest-neighbor twin test false-positives on them (an absent panel's mirrored position is occupied by the OTHER side's forewing, so it reads "twin present") — the surgical mirror shipped a half-wing twice. Panel-level completeness is judged by EYE on ~1500² closeup renders (a rear view showed 2 panels vs 1 instantly). Once the left-right axis is visually proven, bisect at the midline, keep the complete half, and Mirror-modifier the whole model (clip+merge); centered riders/heads symmetrize imperceptibly. Reserve per-component copies for models whose authored asymmetry must survive. (a mobile strategy game: Tripo moth right hindwing, fixed free in Blender on the third attempt — half-mirror across the proven axis.)
- LOCALIZED-REPAIR-PROJECTION — one bad region on an accepted model (the classic: a small-in-
frame face turned to mush) is repaired in TEXTURE SPACE for ~0-9 cr, never by re-rolling the
whole model. Recipe: (1) diagnose with closeup renders — geometry mush vs texture mush;
(2) the concept's own face is usually <40 px, too soft as a repair source — i2i a "closeup
portrait of this EXACT character, same colors, plain white background" from the upscaled head
crop (lands 1:1); (3) project-bake it onto the head in Blender headless: render a PREVIEW from
the projector camera first (that frame IS the projection space — align the portrait to mesh
features in 2D, never by tuning bboxes blind), alpha-key the background and keep only a
feathered face band, then bake
mix(original, canvas, alpha)as EMIT into the basecolor via the original UVs. Two passes are mandatory on faceted low-poly heads: a front cone (normal·front < -0.3) for features, plus the SAME canvas Gaussian-blurred onto side-dominant faces BEHIND the face plane — a single cone either ghosts the face onto the head's side (grazing rays paint every surface in the column) or leaves the old mush at cheek edges, and a normal-only rim band eats the face's own 45° facets. Texture-only output: mesh untouched, every iteration re-bakes from the original texture, material swaps to the new PNG. STYLE-TIER GATE (developer-caught): the re-rendered portrait comes back at a HIGHER detail tier than the unit — realistic shading and micro-detail project as GRAFTED SKIN on a flat-painted low-poly body, and the mismatch is frequency/shading, not hue (palette probes matched). Before projecting: downscale the portrait to the unit's texel frequency (head ≈ 90 px) and re-upscale, then flatten mid-tones ~30% toward the unit's flat skin color (protect darks and lights so features/tusks survive). The source's OWN face at native res is not the alternative — a <30 px concept face upscaled projects as camo-blob mush; re-render then downscale is the only shape with both correct features AND correct tier — BUT for UNIT-TIER subjects this whole portrait path is superseded (developer- mandated): source the repair from the race's own VENDOR PACK REF captures. A generated portrait lands at hero/god detail tier and reads as grafted skin no matter how it's chunked; the pack ref IS the target style by definition. Pack-ref caveats: the ref render carries baked lighting (helmet shadow on the face) — lift to body albedo with per-channel GAIN measured in file space; pack faces are often minimal (nose shading + soft mouth) — extract just the missing feature lines via darkness mask in subject-skin ink (a full-skin patch paste reads as a goatee). Two refinements from the second day: (1) FEATURES-ONLY MASK — when the mesh face has correct skin and only missing DEFINITION (blank eyes), don't project skin at all: mask the canvas to the portrait's dark feature lines (lum threshold + MaxFilter dilate + small blur feather), clipped to the feature columns — original skin stays byte-identical, so there is no boundary and no color problem; (2) COLOR-MATCH IN ONE SPACE — flat renders dim/grey relative to the texture file, so never match file-space portrait colors to render-space mesh samples (overshoots grey); derive the correction as a differential between projected patch and adjacent original skin in the SAME render, apply additively, re-measure — converges in one iteration. (a mobile strategy game war-bat rider + Aelmira god: 9 cr each vs 30 cr rerolls; graft + wrong-color both caught by developer in-editor.) - TEXEL-STARVATION-FACE-SLOT — when a small region (rider/hooded face) stays soft through every texture repair AND through rerolls, the cause is ATLAS TEXEL ALLOCATION, and the fix is a dedicated material slot, not more bakes. A rider face owns ~40 texels of a 2k atlas; nothing baked into those UVs can be crisp, and a regenerated roll inherits the same allocation (a face-crop reroll came back mush-faced — that's the proof to stop). Fix in the SAME one-session normalize script (never round-trip the exported FBX through Blender — import re-bases axes and flips facing): move the head's front-cone faces to a second material slot, rewrite their uv0 to the projector-frame ortho mapping, and drive them with a dedicated 1024² face texture (projector-frame render of the current look composited with the aligned repair canvas — the boundary matches the body by construction). Post: inpaint the render's background color out of the texture (grazing faces sample it) and import with wrap=Clamp (Repeat wraps out-of-frustum UVs into the border). Cost: one extra draw call. Diagnose-first rule: measure/suspect texel density BEFORE iterating projection constants — five bakes were burned on a region that could never hold the detail. (a mobile strategy game war-bat rider: crisp in-engine closeup after the slot; verified with editor-camera renders.)
- Pick the generation provider by BILLING MODEL and capability, not habit — subscription-plan
credits are sunk cost, pay-as-you-go credits are new cash. When a project holds both a
subscription provider (Meshy: monthly plan credits already paid) and a wallet provider (Tripo:
prepaid, 1 credit = $0.01, Stripe recharge, credits never expire), route routine generation
through the sunk-cost plan and spend cash only on capabilities the plan provider lacks. Tripo
(V3 API, base
openapi.tripo3d.ai/v3— V2 dies, never build on a deprecating API version when the retirement date is already announced) uniquely offers: free rig-check + auto-rig 25cr + animation retarget 10cr/anim; Import Model (run rig/texture/retopo on an EXISTING mesh, including another provider's output — cross-provider chains are legal); mesh/part completion (server-side hole repair — test on a copy, inspection gate still applies); deterministicmodel_seed/texture_seed; quad topology andsmart_low_poly. All generation hygiene rules (one subject per input image, two-roll stop, IP gate, flat-background inspection) are provider-independent — apply them to every provider. Wallet balance is a precondition: check the balance endpoint BEFORE promising a task (a freshly-created key can sit at 0 credits with no free grant). (Wired a mobile strategy game: Tripo key added as second provider next to a Meshy subscription.) -
CAVITY-MUSH-REGEN-NOT-PLUG — an open cavity full of AI interior mush that the camera looks into (open cockpit, basket, bay) is a DESIGN defect: seal it at the CONCEPT and re-roll the 3D; do not build occluder geometry over it. (Replaces v58 CAVITY-OCCLUDER-TWO-TIER, which failed developer review the same day it was promoted.) Three escalating Blender plug attempts on one gondola all lost: (1) a rim-level plug poked through the hull — AI hulls are narrower than they look, and per-bin radius fits are polluted by wing roots/straps outside and shreds inside; (2) volume-bounded shred deletion silently DELETED THE PILOT — on island-soup the occupant's body is itself loose sheets, indistinguishable from mush by any size/volume test (the no-heuristics rule wins again); (3) even the contained version (dark cap + floor, occupant intact) still read as a black void at product bar. The working fix cost 39 cr and one prompt: white-bg renders of the ACCEPTED model itself as i2i refs + "recreate this EXACT machine, UNMANNED, opening fully SEALED by a riveted dome hatch, no interior visible" → identity preserved 1:1, and a sealed volume gives reconstruction nothing to hallucinate inside — first-roll clean. Occluder plugs remain legitimate ONLY for holes glimpsed through small gaps (the backed-by-geometry case above), never as the visible floor of an open cavity. Two trailing traps: review the FULL 6-view set before claiming any mesh edit done (the poke-through was visible only in side views nobody re-checked), and when REPLACING a model in-place, re-point the importer material remap at the NEW model's own extracted texture — the old remap silently paints the old skin onto the new UVs as scrambled camo noise. (a mobile strategy game: dwarf war-balloon bay saga, plugs 0 cr wasted, regen 39 cr.)
-
GEOMETRY-VS-ALBEDO-FLATGREY — before "repairing" an apparent hole/dent/tear on an AI mesh, re-render it with a FLAT UNTEXTURED material and fit the primitive it should be. The defect is very often painted into the ALBEDO, and the geometry underneath is perfect. Reconstruction bakes the concept image's dark regions (a shadowed leather flap, a recessed patch, a soot smear) straight into the basecolor; under the flat-ambient inspection lighting those texels read as an OPENING — jagged rim, visible "inner surface", the lot. Every mesh-side repair then fails for the same reason: there is nothing to fill. The 2-minute test that settles it: (1) swap every renderer to a plain grey lit material and re-render the offending view — if the silhouette and shading are clean, the mesh is fine; (2) confirm numerically by fitting the primitive the part should be (algebraic sphere fit over the shell verts:
A = [2p | 1],solve A x = |p|²,r = sqrt(x₃ + |c|²)) and reporting the radial deficit distribution — a real dent shows deficits of tens of percent, a clean shell stays inside a few. Do this BEFORE the boundary-loop census, before any fill-threshold sweep, before any plug. Corollary: an albedo-painted hole is a TEXTURE-tier fix (localized repair → §6f, or a 10 cr retexture that re-rolls the whole look and therefore needs the developer's call), never a geometry-tier one — and partial texel lifts are worse than the original defect, because a half-lifted flap reads as a bright rectangle. Also note the hole DETECTOR cannot see this class at all: a double-sided material paints the far inner surface, so no enclosed background pixels are ever produced and the count comes back clean while the model plainly looks torn. (a mobile strategy game: the dwarf war-balloon's "rip" survived a fill-threshold raise from 0.6 to 3.0 m — 1,025 of 1,033 loops filled, no change — because the envelope was already a closed sphere at 5% max deficit; three cosmetic passes were spent before anyone rendered it grey.) -
GEN-ANIM-IS-LIBRARY-ONLY — no generative-3D service GENERATES animation; they retarget a fixed mocap library keyed by an action id, so "it moves like a human" is a CURATION defect you fix for 3 credits, not a platform limit you accept. Verify capability against the LIVE API, never docs or assumption: Meshy's
POST /openapi/v1/animationsrejectsprompt/text_prompt/video_urlwith "ActionID is a required field",/openapi/v1/text-to-animationreturns NoMatchingRoute, and there is no action-list endpoint (the ~400-entry list is a docs PAGE — scrape it, cache it, and pick from it). Tripo is the same shape. The failure this rule prevents: buying the DEFAULT-looking ids (0 Idle,4 Attack,97 Left_Slash,183 Shot_and_Fall_Backward) for a fantasy monster — that death is a gunshot fall and that idle is a neutral human stand, which is exactly what "stupid human animations" means when a developer rejects a set. Every library has beast/heavy/rage entries hiding in it (Meshy:112 Monster_Walk,119 Slow_Orc_Walk,113 Mummy_Stagger,386 Zombie_Scream,88 Chest_Pound_Taunt,255-257 Angry_Ground_Stomp,99 Reaping_Swing,242 Charged_Slash,237 Charged_Axe_Chop,127 Charged_Ground_Slam,335 Axe_Breathe_and_Look_Around= a weapon-in-hand idle). Read every candidate action's NAME against the unit's fiction before buying — no firearm/reload/phone/dance ids on a fantasy unit, no neutralIdlewhere a combat-stance or breathing-with-weapon idle exists. Structural point that closes the argument: an auto-rigged character IS a Mixamo-spec biped, so every source (library, video mocap, text-to-motion) yields humanoid motion — "creature-like" is a PERFORMANCE STYLE (hunch, wide stance, weight, aggression), selectable at buy time. If a truly bespoke performance is ever required, the only real option is video-to-mocap (DeepMotion/Move/Rokoko) retargeted onto the same rig — not hand-keying. (a mobile strategy game: a demon brute's rejected set became a hunched orc-walk + weapon idle + reaping swing + backward death for 24 credits.) -
WEAPON-FUSED-REGENERATE-NEVER-CUT — when an image-to-3D character was generated holding a weapon, the weapon is REMESHED INTO the body and no Blender surgery recovers it; regenerate the body weapon-free and the weapon as its own asset. The remesher welds blade to hip/thigh/tabard and shatters it into fragments that share vertices with the body, so connectivity-island capture cannot describe the split: taking the islands leaves a blade SLAB fused across the hip while removing the closed fist (a fist is its OWN shell — it leaves with the weapon and reads as "his hand is all broken"), and hole-patching the body afterwards webs FBX UV-seam loops into membranes that stretch open mid-stride. Three rig+clip rolls were burned proving this. Correct flow: (1) image-to-image the SAME character from its approved views with "he holds NOTHING, both hands are empty relaxed open hands" → the identity holds, the hands come out clean; (2) a second generation of the weapon ALONE from a weapon-only asset sheet in the same style; (3) rig the clean body, socket the weapon to the hand bone with its origin at the grip. Also: a clean single-character or single-prop generation needs NO floater cull — keep-largest-island deletes separate armor shells (chest plate) and bbox-overlap deletes boot shells that gap past the pad; cull only what a render actually shows as debris. (a mobile strategy game demon melee: 51 credits of surgery discarded, 134 to regenerate correctly.)
-
VFX-SOLID-FORM-GEN — generative meshes are solid cores for VFX stacks, not whole effects. Projectiles / spell props that need a physical silhouette (crystal bolt, spore pod, rune disc) are valid single-subject gens (same multi-object + provenance rules), but ship them as one layer under stacked additive energy materials (AllIn1 or project equivalent). A bare textured mesh at gameplay camera distance fails the magic look bar. Low poly (≈1k–4k for fliers); pivot at flight center. Full path table: the hybrid section of the VFX with AllIn1 page. (a mobile strategy game — developer required Meshy in the VFX pipeline alongside AllIn1 / Polygon.)
-
STYLE-ANCHOR-LEAKS-ITS-SILHOUETTE — an image passed only as a "style" anchor also donates its shape. An icon set repainted with another item's icon as the style reference came back with a plant fibre twisted into the bone anchor's exact outline and pose (outline overlap 0.68); the item still pointed at its own file, so no reference or GUID check could catch it. Anchor a batch on an item whose silhouette differs from every target, never on a sibling in the set, and gate each roll on outline overlap with its anchor (reject above ~0.65) plus an identical-pixels/shared-file uniqueness test across the whole set.
Free multi-view identity (from a mobile strategy game)
- Free/Imagine multi-view: view_0 only new identity; side/back = image-edit of view_0. Never three independent gens as turnaround.
- Concept bodies: T/A-pose, empty fists for weapon classes, no weapons on body (R11a). >=3 views including air.
IMAGE-GEN-CLI-AND-API-TRAPS
- Codex CLI image runs could not read attachments: its sandbox denies the worktree, user temp and Python
mkdtempfolders, and the elevated sandbox fails its ACLs. Stage inputs in a public folder (<user-home>), run unelevated and close stdin (codex execotherwise waits forever). - A prompt saying "using the attached images" with nothing attached failed 6 of 8 runs ("requested the last N conversation images, but only 0 were available"). Unanchored runs use text-only wording.
- Grok CLI:
grok modelsreports "not authenticated" while-pworks, and images come from its agent tools, not flags. Test a route with one real still, never--help. - Name the transparent-background option on every icon request; rolls came back opaque without it.
- Generated fictional brands can match real companies; check every generated mark before modelling it.
- A reference image in a sparse worktree can be an LFS pointer ("unsupported image image/jpeg"):
git lfs pull. - Meshy: task asset URLs expire after 3 days, so download on success.
DELETEon anIN_PROGRESStask returns 409 and it keeps spending; cancel only whilePENDING. API Remesh/Rigging/Animate cost 5/5/3 credits where the web app shows 0.remove_lightingis honoured bymeshy-6only. 4k geometry failed on thin slabs ("repair did not close the mesh", refunded, cause unknown) where 2k worked. Smart Topology output comes in separate parts, so it breaks a one-closed-piece rule. - A Tripo multiview from a straight front/back pair returned a 0.47 m column: two opposite views carry no depth. Mirror an approved front, or use a multi-image route that includes a side view.
- Patching an image by sampling at a fixed offset lands on the wrong material where a band narrows in perspective; sample by relative position across the band.