source-sdk-2013 icon indicating copy to clipboard operation
source-sdk-2013 copied to clipboard

[Shaders] DecalModulate breaks Underwater due to WaterFogToDestAlpha

Open WhiteRedDragons opened this issue 8 months ago • 0 comments

The Issue: Image Image

Reason(s): When in Expensive Water DecalModulate tries to Render the Height FogFactor into DestAlpha, for the Refractive View This is, uh, opposite of brilliant. The Material DecalModulate is rendering over already rendered the correct FogFactor into DestAlpha. Well just to mention it in case it isn't obvious: DecalModulate always disables AlphaWrites, it couldn't write the FogFactor to DestAlpha if it wanted to. It always requires the alpha output for transparency💯

Reason2: When in Cheap Water, the Material attempts to render regular Fog on itself. The Problem with that is that due to it being underwater it gets very water specific fog values, with a very short range and high strength. The Shader used right now is doing some hacks (pow) to attenuate the Fog Factor This causes inoptimal values for cheap water. Which just to mention it, just like Expensive Water, Cheap Water can handle its own Fog.

Solution: This is downright trivial to fix. Just don't render ANY Fog on DecalModulate when underwater.

NOTE: GetSceneFogMode() is not MATERIAL_FOG_LINEAR_BELOW_FOG_Z when in Cheap Water!! Use GetPixelFogCombo() instead to determine whether or not the Material is in Water. For whatever Reason it returns 1 ( The Value for Height Fog ) in Cheap Water lol

( in case of tf2sdk GetPixelFogCombo1(true) )

What its supposed to look like: Please, ignore the ugly water edge from the stock shader, I got a couple of fixes for that Problem on my custom shader that I haven't fixed up for the tf2sdk yet👍 Image

Trivia: I also fixed the issue of it bleeding through Fog without the pow(). Maybe I'll make another issue about that. An interesting thing to mention here is that aside from GetSceneFogMode() and GetPixelFogCombo() There is a third option to figure out whether or not a material is under the Water-Surface. For those Shader intrigued reading this, g_WaterZ is set for these Materials! ( see also g_FogParams.y ) So simple enough WorldPos < g_WaterZ ? Under Water : Over Water I opted to not use this method for the obvious reason; It tells you if a material is beneath the Water, it can still be outside the water like in a room beneath the water or to the side of it. Which uh yeah for some reason g_WaterZ doesn't get set to a super high value or something when no water is in vis Whole other issue but I find this interesting since it does have some interesting applications and can be abused for mapwide material values without client changes!

WhiteRedDragons avatar Jun 10 '25 01:06 WhiteRedDragons