Mapping & Hammer

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:

FormatBits per pixelAlpha channelSuitable for
DXT141 bit at mostordinary opaque textures
DXT58yestextures with transparency
BGR88824novery fine gradients, normal maps
BGRA888832yesfine 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 > Import and 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 bin folder. It converts TGA files and expects them under garrysmod/materialsrc/. The VTF ends up in the subfolder of the same name under materials/. Settings such as nocompress 1 go 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 to materials/ and without a file extension.
  • $surfaceprop: the surface type, for example concrete, metal, wood, dirt, glass or tile. 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 nearest env_cubemap. They only appear once the cubemaps are built. More in the article on fixing cubemap reflections.
  • $translucent 1 or $alphatest 1: both use the alpha channel of the texture. $translucent allows soft transitions as on glass, but can produce sorting errors between overlapping surfaces. $alphatest only 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:

  1. Put everything into a subfolder of your own. That way you overwrite nobody else's materials and find your files again when packing.
  2. 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

SymptomCauseFix
Pink and black checkerboardThe VMT is missing or $basetexture points to no VTFCheck the path from materials/ and the spelling
White wireframeThe shader in the first line does not existCorrect the shader name
Visible for you, not for othersThe files only exist on your machineShip the material with the map
Surface black or flickeringVertexLitGeneric on a brushUse LightmappedGeneric
Surface glows without shadowsShader UnlitGeneric, which draws without lightingChange the shader
Wrong footstep sound$surfaceprop is missing or does not fitSet 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.