All use of my digital work is covered by this
Creative Commons Deed.
Please do not use any of my work for commercial purposes, thank you.
Spot the Difference
One of the primary effects used in the map
Edge of Forever
was to trigger shaders between different states. It was an essential component
of the environmental immersion because it gave valuable feedback to the player.
The trigger shader commands were a late additions to the
Quake III code base and are available in patch 1.32b.
Most Quake III entities can use these
additional key / pairs but a good example are the
target_relay / target_delay entities.
Click on the above image for a larger version
The Bare Minimum
In order for triggered shaders to work, the following things must be setup:
Entity
The triggered shader is done via a new key / pair which has to
exist on an entity and be triggered to work. The new
key / pair can be setup on most existing entities,
including triggers. (trigger_multiple)
Textures
The source and target texture to be swapped.
Shaders
The textures need to be setup as shaders and the full
path used with the new key/pair on the entity.
Click on the above image for a larger version
Nuts and Bolts
The new triggered shader key / pair:
Source Shader = targetShaderName
Target Shader = targetShaderNewName
-
The source shader name always points to the same
shader name regardless of how many times it changes.
-
The shader name always contains the
full path to where it is defined.
-
The triggered shader affects all relevant surfaces throughout
the map at once.
-
If the target shader is not loaded before the swap
there is a FPS delay.
-
If too many shaders are changed at once the client
will crash with an overflow error.
-
Triggered shaders should have a similar amount of
layers, otherwise a FPS delay.
Light Corruption
When triggering shaders there is a chance that the lightmap can become
too bright / dark or even corrupted. This can happen to any triggered shader
that has a lightmap stage.
The image to the left has four panel lights
and the triggered shaders on
the far left have corrupted lightmaps. This will be noticeable when the shader
is triggered for the first time and then will remain afterwards regardless
of how many times it is changed.
Click on the above image for a larger version
Splitting Hairs
To prevent the lightmap from being corrupted when the shader
is triggered, the original shader should be split into two parts.
The first part is the background texture plus lightmap and the
second part is the triggered effect.
The example shaders below show how the split would happen for
a single stage light switch effect. The tricky part is creating an
'off state' shader, but
using the rbgGen const function the vertex colours can be set
to zero (black) and are then rendered 'invisible' to the player.
The Background + Lightmap shader with the triggered effect removed
With the new shader setup and the various parts
(background + lightmap and effect) split up, the triggered
shader will now only affect what is needed and leave
the rest alone.
The two shaders (background and effect) should be setup
on top of each other. Either using a detail brush or a
simple (3x3) patch so that both surfaces can coexist
with each other and not be removed by the compiler.
The target texture should exist somewhere else in the map so
that when the source texture is triggered, it will not be
loaded from disk but memory. Create a small room
somewhere in the map that the player cannot reach for
storing triggered textures.
Click on the above image for a larger version
The Overload Switch
Each time a triggerable shader is activated the change is transmitted
to all clients. (Q3 is based on client/server architecture) This 'update
packet' is a fixed size and if it fills up quicker than the
engine can transmit, the game will crash.
To see what the engine is transmitting use the console command 'developer 1'
and activate a triggerable shader. As you can see on the console, the
full shader path is used for both source and target strings which can quickly
overwhelm the engine.
Click on the above image for a larger version
The ideal solution is to stagger (use wait keys) all triggerable shaders as
much as possible. It is very likely that if too much is happening at once,
the player will not notice anyway. Try to keep
the number of synchronized changes to a minimum so that the engine
has enough time to keep up.