"s&box won't load my OBJ/GLB"
▸ SYMPTOM
- Dropping an
.obj/.glbintoAssets/does nothing useful in a scene. Model.Load("models/foo.obj")fails or never resolves as a usable model.- The
.vmdlcompiles but materials error with something like:unable to resolve X.vmat. - Model shows untextured / ERROR after a scripted re-export.
▸ CAUSE
s&box does not load raw OBJ/GLB in scenes. The engine compiles a .vmdl wrapper on load. The mesh file is only a RenderMeshFile (and optionally physics) input referenced by that wrapper.
Material remaps must map both names ("MatName" and "MatName.vmat") in the DefaultMaterialGroup remaps, or the compiler errors with unable to resolve X.vmat. A MaterialOverride on the renderer is not a substitute.
Related trap: Blender's OBJ exporter with export_materials=False silently drops the usemtl line too (not just the .mtl file). Remaps key off that material-group name, so the mesh compiles untextured.
▸ FIX
- Put the mesh under
Assets/models/<your-project>/foo.obj(and.mtlif needed). - Emit a sibling
foo.vmdlthat references it.
Minimal wrapper shape (KV3 text, copy structure from any working hand-authored vmdl in your install):
<!-- kv3 encoding:text:version{...} format:modeldoc29:version{...} -->
{
rootNode =
{
_class = "RootNode"
children =
[
{
_class = "MaterialGroupList"
children =
[
{
_class = "DefaultMaterialGroup"
remaps =
[
{ from = "MatName" to = "materials/your/mat.vmat" },
{ from = "MatName.vmat" to = "materials/your/mat.vmat" },
]
},
]
},
{
_class = "RenderMeshList"
children =
[
{
_class = "RenderMeshFile"
filename = "models/your-project/foo.obj"
import_scale = 39.37
import_rotation = [ 0, 0, 0 ]
// translation origin as needed
},
]
},
]
}
}Exact header GUIDs: copy line 1 from a known-good hand-authored .vmdl (citizen addon or your own pipeline output). Do not invent format versions. See also the modeldoc32 trap in ai-generated-models.
After any scripted OBJ export, grep the output for usemtl and vt . If usemtl is missing, re-inject usemtl <name> before the first f line rather than re-enabling material export (which can write a stray .mtl into a delivery folder you don't want).
Load in code with a root-relative vmdl path, forward slashes, no Assets/ prefix:
var model = Model.Load("models/your-project/foo.vmdl");Kick the editor if a new vmdl doesn't show (hot-compile on focus).
▸ WHY IT WORKS
ModelDoc is the compile unit. OBJ/GLB are mesh sources; without a vmdl there is nothing for the resource system to compile into a Model. Remap keys must match whatever string the mesh importer emits for the material slot (some paths emit the bare name, some append .vmat), so mapping both closes the gap. MaterialOverride only swaps at runtime on an already-resolved material group; it cannot fix a failed compile-time remap.