
Article - http://www.simonoc.com/pages/articles/trigshaders1.htm
A small article about triggerable shaders showing how they work and things to avoid. I also created a couple of maps and shader files as working examples. (big download link at the top of page!)
Trying to keep all the information together in one location for ease of searching, previous conversation:
The problem with resetting shaders at the beginning of a map reload is that you can cause the client command line to over run and crash the game. (1024 chars is the limit) The TA shader swap feature always seemed like an engine hack to me and not something that can be done on a larger scale. Ideally there should be a new feature created for this, maybe Eraser could code something better?obsidian wrote:I was searching for our PM discussion about this problem for "Forever" and you beat me to it. Perhaps the player spawn could trigger a relay which resets the original shader state might work to solve the respawn problem?
Here is my PM about shader swapping, if anyone is interested ...
My story so far ...
Solution 1: Originally I used a pair of func_door/buttons to switch shaders around. This was easy to implement and it worked a treat, but Q3 has a 255 hard limit on func items and it is extremely easy to hit this limit if you have multiple brushes for each shader swap. Both brushes have to be in the same position and one has to be moved on start (func_door-start open function) in order to get the lightmaps looking right. The func_ items were moved with -1 speed (instant move) and had the added bonus of additional sound attached to the func_ commands. I originally thought the -1 speed thing was instant but it is not, on one rare occasion I was standing on top of a func_ item and it pushed me upwards as it travelled 'instantly' to its new position. Not really an ideal solution as I was pushed out of the map into the void.
Solution 2: Setup multiple brush surfaces with different shaders and used the remap command via various trigger relay/delay entities. The off shaders were triggered on start of the map to be empty so the 'on' shader was visible. Getting a nodraw texture past the compiler was tricky at first but eventually I settled on the following shader:
Code: Select all
qer_editorimage textures/common/black_nodraw.tga
surfaceparm nomarks
surfaceparm trans
{
map textures/common/black_nodraw.tga
blendFunc GL_ONE GL_ONE
rgbGen const ( 0 0 0 )
}
This solution heavily relied on the 'off' shader being setup at the beginning of the map correctly and I soon found a couple of new Q3 hard limits. When the remap command is run, it is instantly run, no delay and several at once will cause the client command line to over run and crash the game. (1024 chars is the limit) Each setup trigger had to be batched and delayed so they did not all happen all at once. The second limit was a maximum of 128 remap shader commands per map and with duplicates for each trigger this can be reached very easily as well.
The final problem is when the remap command is used, the engine assumes the shader assets used in the target shader are cached/loaded into memory and if not will cause huge fps drops (20-40) while it is loaded. The target shaders have to exist somewhere in the map before the remap command is used, so a small gallery box with a target shader is required.
Other compilications come from the shaders and the best results are when the source/target shaders share similiar/same amount of stages. Going from a 1/2 stage shader to a 4/5 stage shader will again cause huge FPS drops. Going down in stage numbers is fine but huge leaps upwards in stages can be serious. I found the best number of stages to use was 3 (lightmap+source+blend). Some of the more compilicated shaders I was testing with had multiple stages of tcmod commands which again 'seemed' to cause fps slowdowns. Eventually I tried to keep all tcmod stages to a bare minimum and not make the target shader too complex.
Solution 3: Based on solution 2 but removing all the startup remap triggers and using only one shader surface instead of two. The start up of the map was getting to be a huge problem with timing co-ordination and it was easier to just setup the source shaders in the shader file first. This solution involved re-working all the shader file but it did mean the map did not have any startup lag issues.
Unfortunately this solution still had one big problem, lightmaps. When the remap command is used the lightmap on the source shader is broken and will often randomly be full bright, black or a different colour shade to existing surfaces around it. I tried various shader tricks to fix the problem (tcgen lightmap, stylemarker and lightmapscale) but nothing worked 100% all of the time. If anything the various extra shader options just made the problem worse and even more random on which remap surfaces would be broken next compile.
Solution 4: Split the remap shader into two parts. The section to be remapped from the original shader was split into a separate part while the background + lightmap stayed static. Again the shader file had to be re-worked to fit with the new layout but it worked perfectly. The target shaders were cached via the gallery box, the remap shader were single staged so no weird engine redraw lag and best of all, the lightmaps were perfect across all surfaces being remapped.
Example shaders:
Code: Select all
// ----------------------------------------------------------------------
// Stuff to remap (sits on top of background)
textures/moteof/trlit_on
{
qer_editorimage textures/moteof/switch_on.tga
surfaceparm nomarks
surfaceparm trans
{
map textures/moteof/switch_blend.tga
blendfunc GL_ONE GL_ONE
rgbGen wave sin .8 .3 0 0.25
}
}
// ----------------------------------------------------------------------
// Background + lightmap shader (base)
textures/moteof/trlit_background
{
qer_editorimage textures/moteof/switch_background.tga
surfaceparm nomarks
surfaceparm trans
{
map $lightmap
rgbGen identity
}
{
map textures/moteof/switch_background.tga
blendFunc GL_DST_COLOR GL_ZERO
rgbGen identity
}
}
Final solution involved no extra func_ entities, two patches (background and remap surface), various trigger relay's to activate the remap commands and the target shaders cached in a gallery box. The remap shaders were all single stage and this was good news for the engine fps.
I have literally spent weeks on this trying to find the best solution and I think I have found a good one but I imagine the best solution will probably come from ydnar as he knows what the compiler is doing to the remap shader surfaces. (unfortunately he has left the Q3 scene so it is impossible to get his input anymore)