The shader_model tag is used for opaque materials on object models. It supports features like map animation, detail maps, specularity, self-illumination, and color change (e.g. for armour ranks/teams).

Singleplayer units have their colors set in their actor_variant tags. In multiplayer, players' armor colors are hard-coded.

Base map

The Chief's base map, with alpha shown in the top right.

The base map controls the diffuse color and transparency of the shader. The RGB diffuse color is multiplied with the color change source if used, masked by the multipurpose map's color change mask. The base map's alpha channel is a transparency mask.

Multipurpose map

The multipurpose map is an optional bitmap whose individual channels provide greyscale masks for color change, reflections, self illumination, and detail maps (a technique called channel packing). The purpose of each channel depends on the game version:

Gearbox

The Chief's multipurpose map with alpha shown in the top right (Gearbox channel order).

When Gearbox ported Halo to PC, the channels were reordered for an unknown reason. This is also true for all Gearbox-derived ports like H1A unless the OG Xbox channel order flag is set. Because of this change in shader behaviour, multipurpose map tags differ between H1X and Gearbox.

If you're using the legacy HEK and H1CE, don't pay attention to Guerilla's channel usage description when editing this tag. It describes Xbox channel order only which is incorrect. In H1A Guerilla the channel order is corrected described.

  • Red: is an auxiliary mask. It can mask the detail map if the detail mask is set to multipurpose map alpha. Despite the option saying "alpha" in Guerilla it really means the red channel in this context.
  • Green: Masks self-illumination, used for lights on the model. The self-illumination is added to diffuse light and then multiplied with diffuse color, rather than being added after. This means pure black areas of the diffuse map cannot have self-illumination.
  • Blue: Masks cube map specular reflections. Pure blue is highest specularity, while black is none.
  • Alpha: Masks color change, such as for armour ranks/teams. Color sources include the actor_variant, multiplayer colors, and object.

It is a common misconception that multipurpose maps need to be purple due to some stock tags having an identical red and blue channel. However, it is not necessary to have any red channel information if you do not require detail map masking or another channel can serve as the detail map mask.

Xbox

Channel order is different on the classic Xbox version of the game. Guerilla correctly describes multipurpose maps extracted from Xbox maps:

  • Red: Specular reflection mask (modulates reflections)
  • Green: Self-illumination mask (adds to diffuse light)
  • Blue: Primary change-color mask (recolors diffuse map)
  • Alpha: Auxiliary mask

Change color

An animation showing how color change is applied (Gearbox channel order).

The change color feature allows parts of the shader to be recolored at runtime for random variation and different ranks without requiring a different bitmap for each color.

The color from the change color source gets multiplied against the base map, using the color change mask from the multipurpose map. The channel of the mask depends on the channel order (Gearbox vs Xbox).

Change color sources originate from either the object tag's change colors block or are overriden by actor_variant colors. They can also come from hard-coded multiplayer armor colors.

Structure and fields

FieldTypeComments
shader model flagsbitfield
FlagMaskComments
detail after reflection0x1

If enabled, detail maps should be applied over specular reflections. This flag does not work as intended in the Gearbox renderer but can be worked around with Chimera or CEnshine. It is fixed in H1A.

two sided0x2
not alpha tested0x4
alpha blended decal0x8
true atmospheric fog0x10
disable two sided culling0x20
multipurpose map uses og xbox channel order0x40
  • H1A only

If enabled, the multipurpose map will use Xbox channel order instead of Gearbox order.

translucencyfloat
change color sourceenum
OptionValueComments
none0x0
a0x1
b0x2
c0x3
d0x4
shader model more flagsbitfield
FlagMaskComments
no random phase0x1
color sourceenum?
animation functionenum
OptionValueComments
one0x0
zero0x1
cosine0x2
cosine variable period0x3
diagonal wave0x4
diagonal wave variable period0x5
slide0x6
slide variable period0x7
noise0x8
jitter0x9
wander0xA
spark0xB
animation periodfloat
  • Unit: seconds
  • Default: 1
animation color lower boundColorRGB
animation color upper boundColorRGB
map u scalefloat
  • Default: 1
map v scalefloat
  • Default: 1
base mapTagDependency: bitmap

A bitmap which provides diffuse colour and transparency information to the shader. See details.

multipurpose mapTagDependency: bitmap

A bitmap which provides masks for reflection, self-illumination, colour change, and detail maps. See details.

detail functionenum
OptionValueComments
double biased multiply0x0

The detail colour is multiplied with the base colour and multipied by 2, then clamped to 0-1. Where detail is masked, this has no effect. Unlike the S-shaped response curve of Photoshop's Overlay blending mode, this function continues to brighten exponentially and quickly saturates when the detail map is lighter than 50% gray.

detail = lerp(0.5, detail.rgb, detail_mask);
result = saturate(base.rgb * detail * 2.0);
multiply0x1

The detail map is simply multiplied with the base colour, generally darkening the result. Where detail is masked, this has no effect.

detail = lerp(1.0, detail.rgb, detail_mask);
result = saturate(base.rgb * detail);
double biased add0x2

Has the effect of adding or subtracting the detail map to/from the base map. Where detail is masked or 50% gray, this has no effect.

detail = lerp(0.5, detail.rgb, detail_mask);
biased_detail = 2.0 * detail - 1.0;
result = saturate(base.rgb + biased_detail);
detail maskenum

Determines the source of detail map masking.

OptionValueComments
none0x0
reflection mask inverse0x1
reflection mask0x2
self illumination mask inverse0x3
self illumination mask0x4
change color mask inverse0x5
change color mask0x6
auxiliary mask inverse0x7
auxiliary mask0x8

Use the "auxiliary mask", which is the alpha channel on Xbox and the red channel in Gearbox-derived ports.

detail map scalefloat
  • Default: 1
detail mapTagDependency: bitmap
detail map v scalefloat
  • Default: 1
u animation sourceenum
OptionValueComments
none0x0
a out0x1
b out0x2
c out0x3
d out0x4
u animation functionenum?
u animation periodfloat
  • Unit: seconds
  • Default: 1
u animation phasefloat
u animation scalefloat
  • Unit: repeats
  • Default: 1
v animation sourceenum?
v animation functionenum?
v animation periodfloat
  • Unit: seconds
  • Default: 1
v animation phasefloat
v animation scalefloat
  • Unit: repeats
  • Default: 1
rotation animation sourceenum?
rotation animation functionenum?
rotation animation periodfloat
  • Unit: seconds
  • Default: 1
rotation animation phasefloat
rotation animation scalefloat
  • Unit: degrees
  • Default: 360
rotation animation centerPoint2D
FieldTypeComments
xfloat
yfloat
reflection falloff distancefloat
  • Unit: world units
reflection cutoff distancefloat
  • Unit: world units
perpendicular brightnessfloat
  • Min: 0
  • Max: 1
perpendicular tint colorColorRGB
parallel brightnessfloat
  • Min: 0
  • Max: 1
parallel tint colorColorRGB
reflection cube mapTagDependency: bitmap
unknownfloat
  • Cache only

Acknowledgements

Thanks to the following individuals for their research or contributions to this topic:

  • Giraffe (Animation for change color masking)
  • Jakey (Discovering that self-illumination is added to diffuse light, not diffuse color)
  • Kavawuvi (Invader tag definitions)
  • MosesOfEgypt (Tag structure research)
  • t3h lag (Explaining multipurpose map channels)