Create Custom Textures for GMod: VTF and VMT Explained
Custom textures for Hammer and GMod: save the image as a VTF, write the VMT, put the files in the right place under materials and fix typical errors.
Your own image becomes a texture when you save it as a VTF and add a small .vmt text file that describes the material. Both files belong in a subfolder of garrysmod/materials/. Hammer and the game always work with the material, the VMT, which points to the VTF. With the right image size, shader and path, the texture shows up in the Texture Browser and in game.
Two files: VTF and VMT
The VTF (Valve Texture Format) holds the image data: the pixels and the mipmaps, smaller versions for use at a distance. The VMT is a text script. It defines which shader draws the surface, which textures it uses and how the surface behaves physically, such as its footstep sound.
The engine does not access a VTF directly, only through a material. That is why you pick materials in Hammer, not image files. Several VMTs may use the same VTF, for example one for brushes and one for models.
Preparing the image: size and format
Width and height each have to be a power of two, for example 256, 512, 1024 or 2048 pixels, normally 4096 at most. The image does not have to be square, 512 × 256 works. Save the source image losslessly, for example as TGA or PNG. A JPG brings artefacts with it that get compressed again during conversion.
When saving as a VTF you choose an image format. Four of them cover almost everything:
| Format | Bits per pixel | Alpha channel | Suitable for |
|---|---|---|---|
| DXT1 | 4 | 1 bit at most | ordinary opaque textures |
| DXT5 | 8 | yes | textures with transparency |
| BGR888 | 24 | no | very fine gradients, normal maps |
| BGRA8888 | 32 | yes | fine gradients with an alpha channel |
The DXT formats compress with loss, the other two do not. The price is size: without mipmaps, a 1024 × 1024 texture takes half a megabyte as DXT1 and three as BGR888. So default to DXT1 or DXT5 and use the uncompressed formats only where the compression visibly distracts. For textures in the 3D world, have mipmaps generated.
Converting the image to a VTF
Two routes are common:
- VTFEdit and its successors. VTFEdit is a graphical program. You load the image via
File > Importand set the format in the import dialog under "Normal format" and "Alpha format". According to the Valve Developer Community, the original is no longer maintained. The community continues it as VTFEdit Reloaded and VTFEdit++. - vtex. Valve's command line program ships with GMod in the
binfolder. It converts TGA files and expects them undergarrysmod/materialsrc/. The VTF ends up in the subfolder of the same name undermaterials/. Settings such asnocompress 1go into a text file with the same name as the image.
Mind the VTF version when saving: 7.4 or older is the safe choice. Version 7.5 comes from a newer engine branch, and for GMod the Valve Developer Community only says that support is possible.
Writing the VMT
Any text editor can create a VMT. The smallest sensible wall material looks like this:
LightmappedGeneric
{
$basetexture "myname/mymap/wall_concrete01"
$surfaceprop concrete
%keywords "mymap"
}
The first line names the shader, and each line between the braces holds a parameter and its value. Quotation marks are only needed when a value contains spaces. You need these parameters first:
$basetexture: the path to the VTF, relative tomaterials/and without a file extension.$surfaceprop: the surface type, for exampleconcrete,metal,wood,dirt,glassortile. It determines footstep sounds, bullet impact effects and other physical properties.$bumpmap: a normal map that gives the surface structure under light. If you add it later, recompile the map, because such surfaces get additional lightmaps.$envmap env_cubemap: reflections from the nearestenv_cubemap. They only appear once the cubemaps are built. More in the article on fixing cubemap reflections.$translucent 1or$alphatest 1: both use the alpha channel of the texture.$translucentallows soft transitions as on glass, but can produce sorting errors between overlapping surfaces.$alphatestonly knows visible or invisible, is much faster and suits fences and grates.%keywords: comma-separated keywords for the "Keywords" field in Hammer's Texture Browser.
Folders and paths
garrysmod/materials/myname/mymap/wall_concrete01.vmt
garrysmod/materials/myname/mymap/wall_concrete01.vtf
garrysmod/materials/myname/mymap/wall_concrete01_normal.vtf
The name of the material in Hammer is the path of the VMT from materials/ onwards, here myname/mymap/wall_concrete01. Where the VTF is and what it is called does not matter technically, as long as $basetexture points there. Matching names are just the usual convention.
Two rules save you trouble:
- Put everything into a subfolder of your own. That way you overwrite nobody else's materials and find your files again when packing.
- Write folder and file names in lower case, without spaces or special characters. Linux servers are case-sensitive.
GMod also loads everything under garrysmod/addons/<name>/materials/. If a new material does not show up in the Texture Browser, restarting Hammer helps in practice.
Brushes and models: the right shader
LightmappedGeneric is meant for brushes and displacements. These surfaces are lit by the lightmaps VRAD calculates. VertexLitGeneric is the shader for models, whose light is determined per vertex.
If you mix the two up, the lighting is wrong. According to the Valve Developer Community, a VertexLitGeneric material on a brush shows as a surface that is completely black, flickers or changes brightness with the viewing angle. That is why materials from the models/ folder do not belong on brushes. Conversely, models cannot use LightmappedGeneric. For the same image on a brush and on a model, write two VMTs that point to the same VTF. Usually only the first line differs.
Typical errors and their cause
| Symptom | Cause | Fix |
|---|---|---|
| Pink and black checkerboard | The VMT is missing or $basetexture points to no VTF | Check the path from materials/ and the spelling |
| White wireframe | The shader in the first line does not exist | Correct the shader name |
| Visible for you, not for others | The files only exist on your machine | Ship the material with the map |
| Surface black or flickering | VertexLitGeneric on a brush | Use LightmappedGeneric |
| Surface glows without shadows | Shader UnlitGeneric, which draws without lighting | Change the shader |
| Wrong footstep sound | $surfaceprop is missing or does not fit | Set a matching value |
If the whole map is evenly bright and not just one surface, the lighting data is missing. That is covered in the Source Engine lighting guide. If you changed a VMT while the game is running, the console command mat_reloadmaterial plus the name of the VMT reloads it.
The case "not visible for others" is the most common. Custom materials only exist in your game folder until you ship them. How to do that is described in packing custom content into the BSP, and the player's side in fixing missing textures and ERROR models. Only use images you hold the rights to: your own photos and graphics, or sources whose licence allows redistribution. The basics are in GMod map copyright basics.
FAQ
What resolution should a texture have?
That depends on the surface. Hammer applies new textures at a scale of 0.25, so one pixel covers a quarter of a unit and a texture 512 pixels wide repeats every 128 units. Higher resolutions look sharper up close but cost memory and file size.
How do I make a fence or a grate see-through?
The image needs an alpha channel in which the gaps are black, and the VTF a format that stores it, usually DXT5. In the VMT you write $alphatest 1. The example on the Valve Developer Community also sets $alphatestreference 0.5 as the threshold between visible and invisible. If the surface should be visible from both sides, add $nocull 1.
Does every texture need a normal map?
No. A material works with $basetexture and $surfaceprop. A normal map costs another VTF, and surfaces with $bumpmap get four lightmaps instead of one. It pays off where grazing light should reveal structure.