FIELD NOTES

NOTE 03 · FROM IMAGE TO MODEL

From concept sheet to a model that can enter the game

After asking a large model to produce a game-ready 3D character failed, I split the task into much narrower stages. This is the record of that route.

What follows is a developer's personal record, including internal milestones, technical decisions and failures. It describes the current state — not a final form, and not a release commitment.

The shortcut that did not work

At the start I wanted to go straight from a concept sheet to a model that could enter the game.

The reasoning looked sound. The sheet already fixes the shape, the palette and the weapon. A model is just its three-dimensional version. So handing the sheet to a strong enough model and letting it infer the mesh should be the shortest path.

The problems showed up quickly.

Not "it doesn't look good" — the output often looked good. The problems were:

  • The structure did not hold. The front view and the top view were not two projections of the same object.
  • The hands were unreadable. Where is the grip? Which hand does the weapon come out of? No answer.
  • Weapon silhouettes turned to mush. The tooth line of an axe, the width of a sword, the thickness of a guard all became "roughly that idea."
  • And the fatal one: it could not be verified. I cannot point at a semantically vague mesh and say "this part is wrong," because I cannot say which part this is. Something you cannot locate an error in is also something you cannot fix.

So I stopped — not because the model was too weak, but because I had asked the wrong question.


2. Narrowing the task

I then split it into a chain of narrower stages, each of which passes or fails on its own:

  1. Fix the visual intent. A production sheet is a structure contract, not a reference image. Each one carries a single character identity, consistent orthographic/multi-angle views, a silhouette, a palette, equipment isolates, a part breakdown and dimensional cues. Every view preserves the same body, costume, palette, handedness, weapon dimensions and attachment count.
  2. Zero-cost pre-checks. Before any paid call: single subject, same identity, same pose, complete limbs, correct handedness, size and hashes, and a consistency audit between front/side/back and a true orthographic top. When the top disagrees, fix and version the input first — do not make the generator carry the blame for a broken input contract.
  3. Meshy does base geometry only. Image-to-3D / multi-image-to-3D, defaulting to a topology-first task with should_texture=false and should_remesh=false, answering exactly one geometric hypothesis at a time.
  4. Deterministic local derivation. Mesh and structure repair, proportion correction, part decomposition, colour binding.
  5. Rigid-part attachment and animation adaptation.
  6. Import into Godot and verify in the running game.
  7. Human visual approval.

Stage 3 is the only paid step and the only uncertain one. Everything else is a deterministic local process.


3. Why the runtime has no skeletons

There is a hard rule on the Godot side that sounds strange out of context: characters use no Skeleton3D, no Skin and no BoneAttachment3D. The visual adapter actively rejects resources containing them.

Characters are rigid_parts: one merged ArrayMesh per logical part, sharing a single voxel pitch (0.019 m). The runtime never loads a raw GLB — the Meshy source GLB is archival material under art/source/meshy/, with a .gdignore, a credit ledger and a SHA-256 registry, existing only as the input to a deterministic derivation chain.

Why do it this way?

  • Voxel-style characters are already made of blocks, so rigid parts cost nothing visually;
  • merged meshes keep draw calls controllable, which matters at twenty enemies on screen;
  • and most importantly, it can be verified. A rigid part is either in the right place or it is not. "The skin weights look slightly odd" cannot be written into a validator.

Gameplay code only knows a visual_id and action names. It does not know which chain the model came from, how many parts it has, or whether it is the Meshy-derived set or the pure-Godot fallback — the backend swap is one runtime option.


4. Character proportion is a number, not a feeling

The approval states the runtime height ratios explicitly: Goblin 0.68, Swordsman 1.00, ordinary Minotaur 1.72, Boss 2.45.

That matters because apparent scale in the generated raster is compressed, and that image has no authority over runtime dimensions. The approval explicitly waives the raster's proportions and recognises only these numbers.

Fidelity is measured as rendered silhouette IoU against a uniform 0.55 threshold:

| Character | Silhouette IoU | | --- | --- | | Swordsman | 0.611897 | | Goblin | 0.600124 | | ordinary Minotaur | 0.681249 | | Boss | 0.560647 |

The Boss sits just above the line. I keep the number because it honestly says "barely passed."


5. I sent the Boss back

The evil minotaur rework went like this.

V4 was rejected. Two specific reasons, both visible to me in the formal boss_roar frame: a structural discontinuity in the anatomical-left wrist and arm, and a crescent axe blade that was not sharp enough.

Note what kind of reasons those are. They are named structural defects, not "I don't like it." That distinction decides the next move: a named defect can enter a correction flow, and pure taste can be a clean STOP. Neither becomes a random reroll.

V4 stays as byte-immutable rejected history. It is not deleted and not overwritten.

V5 was one additive, local-only correction targeting exactly those two defects.

V6 rebuilt the wrist as a single slim wide-to-narrow tapered armoured bracer, and replaced the weapon head with a larger seven-tooth, six-valley, two-sided bull-horn-eye tribal axe.

V6 passed and moved to runtime promotion. No threshold was quietly loosened along the way — "a marginal failure fixes the derivation first; it does not probe formal repeatedly, and it never relaxes the threshold in reverse" is written into the rules.

Goblin and ordinary Minotaur recovery took longer: Phase A, Phase B Wave-1, and Wave2 v2 through v6. I accepted the result at Wave2-v6 and called a stop myself — not because it is perfect, but because the marginal return on further iteration had dropped below its cost. That stop rule is in the document too: reopening for a v7, a Phase C or a paid correction needs a new explicit decision.

The Wave2-v6 formal machine seal covers 192 artifacts. Runtime promotion itself added no network call, no generation task and no credit spend — it repointed a pointer.


6. Who is on the roster

Only confirmed identities are published: Swordsman, Vampire, Goblin, Minotaur and Evil Minotaur.

The CLASSIFIED silhouettes on the characters page are not theatre. They correspond to things that genuinely exist in the repository and have not finished their approval path. Until they are formally confirmed I publish no name, no background and no design for them — and I do not imply that the current design is final, because based on this project's history it very likely is not.


7. What I took from this route

AI is very strong at finishing a well-defined problem and very weak at defining the problem for you.

My first failure was not a tool limitation. It was handing over a task I had not thought through myself. The moment "give me a character that can go in the game" became "from these five consistent orthographic views, produce a base geometry satisfying these occupancy constraints," the success rate changed.

And one more, probably the more important one: leave room for failure. The rejected V4 is still in the repository, unchanged to the byte. The zero-Event run is still in the record. A process that only keeps successes is not recording development — it is recording a story assembled afterwards.