Starship Horizons
Log In
☰
Knowledge Base›Models Textures And Shaders

Models Textures And Shaders

Art is not simply dropped in. A model is registered, with its materials described, and the game then resolves it by name. Registration is where most art problems live.

Registering a model

<model name="Ark" source="ark.fbx" format="Standard" collision-source="Ark-Collision"
       group="Vessels" rotation="0 0 0" scale="0.7559546">
  <mesh id="0" format="Standard"
        texture="ark.jpg"
        texture-normal="ark_norm.jpg" texture-emissive="ark_light.jpg"
        texture-arm="ark_arm.jpg" blending="Color"
        metalness="0" roughness="1" emissive-intensity="1" />
</model>
<model name="Ark-Collision" source="ark_collision.fbx" format="Collision"
       group="Vessels" scale="0.7559546" />

The record names the file, a scale, a rotation correction, and one entry per mesh describing that mesh's material. name is how everything else refers to it.

FBX and glTF/GLB are both supported. Scale is almost always needed — modeling tools and the game do not agree on units, and the scale figures in real content are arbitrary numbers found by eye.

A <mesh> entry's own name binds it to the surface of that name in the file, and it is the reliable way to address one. An entry with no name falls back to its id as an index, but the server and the renderer can count a file's surfaces differently, or in a different order, so an index can point at a surface you did not mean. Where the two disagree, the editor's Mesh tab says so: give those entries names. A named entry that matches nothing paints nothing rather than guessing. A model with a single entry is treated as one material, and that entry applies to every surface.

Two model attributes control how the art takes part in the scene. cast-shadows="false" keeps a model out of the shadow pass on a map that draws shadows, while it still receives them: use it for sky sheets and other geometry the sun should ignore. travel-stretch="true" is for streaks and tracers: the model is never drawn longer behind its origin than its object has traveled, so a missile streak grows out of the launcher instead of poking out of the back of whatever fired it.

Material formats

The format chooses the shading model:

  • Basic — unlit. For anything that should not respond to light: projectiles, effects, glowing elements.
  • Phong — classic specular shading, driven by specular and normal maps. Older art that has not moved to Standard: in the base game, mostly asteroids, debris, weapons and a few small craft.
  • Standard — physically based, with metalness and roughness. What to use for new work.

Texture slots are diffuse, specular, normal, emissive, and a packed ambient‑occlusion / roughness / metalness (ARM) map. Standard reads the ARM map and ignores specular; Phong reads specular and ignores ARM. Emissive is what makes a ship's windows and running lights read at distance, and it does more for a model's presence in space than any other single map.

The numeric settings apply on top of the maps: metalness and roughness on Standard, shininess and reflectivity on Phong, and emissive-intensity on both. A value left at its default (metalness 0, roughness 1, shininess 30, reflectivity 1, emissive intensity 1) changes nothing, which is what lets an ARM map's own metalness and roughness stand.

blending selects how the mesh composites — Color for ordinary solids, Additive for anything that should glow through what is behind it, Multiply to darken what is behind it.

Compressed textures (KTX2)

A JPEG or PNG is unpacked to full size in video memory, so one 4096 × 4096 map costs about 85 MB of VRAM however small the file is. A KTX2 file holds GPU block‑compressed data that is uploaded as it is: a quarter to an eighth of the memory, at the same resolution, and decoded off the main thread.

You do not change models.xml to use one. Put a .ktx2 with the same base name beside the texture — ark_norm.ktx2 next to ark_norm.jpg — and the server hands the client the KTX2 instead, for every map slot on a model's mesh entries. A slot can also name a .ktx2 directly.

The engine reads KTX2 but does not make it. Encode with Khronos's KTX‑Software (ktx create), and follow four rules, most of which fail quietly:

  • Bake the orientation in. A compressed texture cannot be flipped as it loads. Maps used by an FBX model must be written flipped vertically; maps used by a glTF model must not be. A texture both formats use cannot be converted at all: give each format its own copy.
  • Match the color space to the slot. Diffuse and emissive maps are color and want the sRGB transfer function; normal, specular and ARM maps are data and want linear. The file's own setting wins, and a mismatch is reported in the browser console.
  • Use UASTC for normal and ARM maps. The smaller ETC1S encoding is fine for color and specular, but it blends channels that a normal or ARM map needs kept apart, and a damaged normal map renders as black facets. UASTC files are larger to download, so 2048 is usually the right size for those two slots. Do not use the two‑channel normal‑map mode: the renderer does not rebuild the third channel.
  • Generate mipmaps in the file. The renderer uses the file's own mip chain and cannot build one, so a file without mipmaps shimmers on a distant surface.

Collision

A separate collision-source mesh is worth providing for anything large. Collision against full display geometry is expensive, and a simplified hull is both faster and better behaved.

collision-source names another registered model, not a file. Register the simplified hull as a model of its own, with format="Collision" and its own scale, and name that, as the Ark example does. A name that matches no model is not reported: the object silently collides with its display mesh instead.

Shaders and effects

A model or mesh entry can carry an effect attribute naming a shader registered in World/shaders.xml. The current renderer does not read it: every model draws through the material formats above, and the attribute is kept only so that it survives a save. Do not rely on it to change how a model looks.

What a model can carry is effect placements: child <effect> elements, each naming an effect bank and where it hangs in model space.

<model name="CT1" source="ct1.glb" format="Phong" group="Scenery" scale="1">
  <effect class="Smoke Stack" name="Stack" position="0 38.5 0" />
</model>

They play wherever the model is placed as scenery, so a piece of set dressing that smokes or flares does not need a second model placed on top of it in every map. Any other attribute on the element is handed to the bank's renderers as a parameter override. A ship's effects belong on its vessel class instead.

Traps

A glTF with its own maps keeps them. When a glTF file carries texture maps, its materials win, and the mesh entries' texture and material settings are ignored; only colorize still applies, and the editor's Mesh tab says so. A glTF exported as geometry only, and every FBX, takes its materials from its mesh entries. Which side owns the material is the first thing to check when a model imports looking nothing like it did in your modeling tool.

glTF and FBX disagree about texture orientation. The vertical axis runs the other way, so the game loads a glTF model's maps unflipped and an FBX model's flipped. For ordinary images that is automatic, and one image can serve both formats. A KTX2 file has one orientation baked in, so there it is your job (see above). Get it wrong and the normal map lights the surface backwards — the symptom is black facets and a model that looks flat and dead rather than obviously broken.

Cloned models share materials. Changing a material at runtime affects every instance, and texture caching is keyed on load settings, so a change that appears to work on one ship can silently apply to all of them.

Do not assume a path exists. Assets resolve through the merged index of every active module, so a texture your module references may be coming from somewhere else entirely — and a path that works on your machine may not exist for someone with a different module set. See Modules for the resolution order. Base game art moves too: its backdrops are WebP files now, and several textures have been removed, so a reference to a base game file by an old name finds nothing.

Previewing

In Hydra, a module's Models section is a browser: the list, grouped and searchable, with a live 3D view of the selected model beside it. Edit opens the model in its own tab, with Details, Mesh and Animations tabs beside a full‑size view. Mesh edits show in the view as you type them, built by the same material code the game uses, so what you see is what will load. The Gallery station also shows registered art without launching a mission.

Use them: the loop of registering, looking, and adjusting scale and materials is much faster there than in the game.

Last updated 19 October 2026