All the graphics in Quake3 - rooms, players, icons, text, menus etc. - are made out of polygons. Shaders are simple scripts that are used by the Quake3 engine and its compile tools to determine the properties of the polygon surfaces and how they are rendered.
The most common use of shaders is to control the properties of walls in levels. In Quake1 a wall surface would point directly to the texture that would be painted on it. Quake2 added a number of surface properties which allowed the surface to be made, among other things, transparent and like water. In Quake3 every wall surface points to a shader. The shader tells the Quake3 and its compile tools if, among other things, the surface is transparent, whethers it's water or lava, or if the surface is part of a clip brush, what texture map to use, how to make it transparent, and whether it's a portal or not.
A shader file is a text file containing a series of shaders. They are stored in the scripts directory of the current game directory or .pk3 file and always have a .shader extension.
// a comment
[the shader name]
{
[surface attributes]
// a stage
{
[stage attributes]
}
[more stages]
}
This is the general layout of a shader. The parts in italics are explained below.
Shader files can include comments which are ignored by the Quake3 engine. Comments start with a two forward slashes and finish at the end of the line.
Every shader starts with its name. This is just a simple string like textures/base_floor/diamond2c. A shader name must be less than 64 characters in length and lowercase. If any slashes are used they must be forward slashes.
The rest of the shader is contained in curly brackets. This is called the shader body.
Surfaces attributes control the behaviour of the overall polygon surface to which the shader is linked. For example, it might tell q3 that characters should not make the footsteps sound when on it. A surface attribute is an identifier (name) followed by zero or more parameters. Only one surface attribute is allowed per line.
Example:
surfaceParm noMarks
The surfaceParm is the identifier. The noMarks is a parameter.
A stage is like a layer in photoshop. Zero or more stages are rendered one after the other. A stage is formed from a number of stage attributes enclosed in curly brackets.
Example:
{
aStageAttribute
anotherStageAttribute
}
Stage attributes are just like surface attributes.
Example:
map textures/base_floor/diamond2c.tga
This tells q3 to use that texture for this stage.
A shader is drawn by drawing each stage in turn. Each stage has at least a texture. For example, the first stage might be a lightmap. This is a texture where the colours correspond to the amount of light falling on the surface. The next stage might be a normal wall texture which is blended with what has already been drawn (i.e. the lightmap) to give the impression that the texture has light and shadow falling on it. If you've used layers in Photoshop it's very similar.
Here's a sequence of images showing what happens.
First we have the textures we're using.
Lightmap:
Wall texture:
Here's what the scene looks like before we draw the shader:
Here's what the scene looks like after the first stage of the shader, the lightmap, is drawn:
Here's what the scene looks like after the second stage of the shader, the wall texture, is blended in:
Et voila. Note that if the first stage had a blend, it would have been blended into what was already drawn.
textures/base_floor/diamond2c
{
surfaceParm noMarks
{
map $lightmap
}
{
map textures/base_floor/diamond2c.tga
blendFunc filter
}
}
This shader is like the one described in the previous section. The first stage contains a lightmap texture and nothing else. The second stage contains a normal texture and a blendfunc to tell q3 to blend it with what's already on the screen. There's also a surfaceparm surfaceattribute in there for no particular reason.
Shader files must be given a unique name. In almost all cases it'll be the name of your map or model. Do not use generic names like, say, wall.shader. If you use the same name as a shader provided with q3 you will go to hell (that includes you Zoid :p ).
Shaders must also be given unique name. That includes unique with respect to textures, i.e. a shader must not have the same name as a texture. This is not a strict requirement, but it does save a lot of confusion. Your shader name should start with the same name as your .shader file. If your .shader file is called majq3dm1.shader, your shaders should be named something like majq3dm1/my_shader.