Decided to check out how water is rendered in Counter-Strike 2 Given how interactive water in CS2 is, I expected to see some cell fluid simulation, but turns out they use just a low-res off-screen buffer with flat 2D decals for various water effects. Reminds me of HL2 water :)

Jun 11, 2025 · 1:18 AM UTC

15
181
15
2,471
Buffer size is ¼ of the horizontal and ½ of the vertical screen resolution. Red is used for waves and caustics. Green is used for splashes and foam. Blue is used for dust and trails on mud/junk on the water surface. Everything is rendered using flat 2D textures.
1
8
1
259
Water is rendered as flat plane, waves (and all other effects) are created using pixel shader Shader receives framebuffer and depthbuffer as input. Both caustics, refractions, and reflections are handled entirely in screen space (with some backing from parallax-correct cubemaps)
2
6
150
As a result of this approach, slight pixelization and some screen space artifacts can be noticed. Although screen space reflections look pretty decent here, reflections aren't very pronounced and parallax-corrected cubemaps hide most of the SSR flaws.
1
2
67
Caustics seem to be divided into procedural and off-screen buffer ones While the procedural ones are consistent with underwater geometry, the others appear at some arbitrary depth (to save perf on reprojection?), and disappear if you look away (tho it's REALLY hard to notice)
1
3
102
0
I also noticed one place where foam from one water surface was rendered on another water surface at different height, causing some parallax issues.
2
1
95
0
Since I've started to examine how CS2 renders a frame, I decided to look at other aspects of it's rendering pipeline as well. The first thing I wanted to look at is lighting. CS2 mixes baked lighting with shadow maps, per-pixel lighting and capsule ambient occlusion.
1
2
61
Baked lighting is stored in 3 textures. One HDR texture for static lights and GI. One LDR texture for baked light direction. It's also half res on some maps. And one more texture is used to store from 1 to 4 shadow masks for semi-dynamic per-pixel lights.
1
4
59
Shadow masks are used to combine shadow maps with dynamic props and players with baked penumbra shadows from static geometry. You also get per-pixel shading with proper normal mapping and specularity. All shadow maps are rendered into one big atlas at the beginning of the frame.
1
1
46
Light probe volumes are used to light dynamic objects. Data is stored in two large 3D texture atlases. The first one is HDR and is six times larger than other (looks like Valve is still using ambient cubes). The second one is LDR RGBA, looks like a shadow mask.
2
1
42
CS2 uses parallax-corrected cubemaps as it's main method for reflections. All cubemaps are stored in one large texture array. Pre-filtered mipmap are used for smooth rough reflections (looks really nice when used with roughness maps).
2
2
51
Z-Prepass is performed after shadow maps are rendered and is used as input for capsule-based (probably) AO.
1
1
26
AO is calculated in half-res RGB buffer. Box is rendered around each dynamic object, with soft shadows from 3 directions stored as RGB. This data is then used in the main rendering pass, where the AO direction is selected based on the light direction from the lightmap.
2
2
41
Decals are rendered after all solid geometry. Some flavor or parallax occlusion mapping is used (no fancy cone step mapping here). Textures are projected using data from z-buffer, which can cause artifacts when anti-aliasing is enabled.
1
1
39
CS2 also uses some flavor of order-independent transparency for particles, glass, smoke and fire. Most likely, moment-based OIT is used.
1
1
26
Two render passes and one composing pass is used for transparent geometry (see moment-based OIT) First pass uses 3 render buffers (R 32F, RG 32F, RGBA 32F) Second pass uses previous as input and renders color data in RGBA 16F buffer Final pass combines this data with framebuffer
1
1
31
Smoke is rendered separately in a bunch of low-res buffers and is combined with OIT buffers later. A whopping SIX (!) buffers are used (R 32F, RG 32F, RGBA 32F, RGBA 16F, RG 16F, R 8UI). The first 4 buffers seem to be the same as the OIT buffers, but I'm not sure about the rest.
1
27
Two sets of buffers with different resolutions are used for smokes at different distances. Close ones are rendered in ¼ buffers, and distant ones in ½ buffers. Fire is also rendered separately and merged with OIT later, but only 4 ½ res buffers are used.
1
30
The next one in the render is water, but I've already covered it earlier. Only after all of this the player viewmodel is rendered. CS2 has a separate pass for the viewmodel SSAO, which feels like overkill to me.
1
37
I also wanted to check out that famous bottle shader, but I don't think that I can pinpoint anything useful without examining shaders All I see is that bottle is fully opaque and doesn't use colors from framebuffer. Only cubemaps and per-pixel lighting are used for refractions
1
60
Replying to @Hillsguy2
>expected to see some cell fluid simulation AHHAAHHAHAHAHAHAHAHAHHAHAHAHAHAH
Yeah, I expected to see something similar to water from Baldur's Gate: Dark Alliance from PS2 or Blinx: The Time Sweeper from Xbox
2
Replying to @Hillsguy2
what is this, a sane individual just showing how source 2 works without nonsense? incredible, ever considered working on source2 viewer? we need more people like you haha
19
Replying to @Hillsguy2
And yet, they managed to make it look like a real AAA game water. There are high budget games that do not have such good looking water.
2
8
Replying to @Hillsguy2
Maybe Apple can learn a thing or two from this! Hey @apple, check this out!
3
Replying to @Hillsguy2
As a person just getting into gamedev, this is an awesome thread. Thank you!
3
Replying to @Hillsguy2
This is such a good breakdown. Thanks for sharing!
2
Replying to @Hillsguy2
And it looks great!
1
Replying to @Hillsguy2
Bro, do you have a blog? Such wonderful content can be published in a blog.
Replying to @Hillsguy2
Well whatever works. Even without fluid simulation. I'll take this over that.
Replying to @Hillsguy2
That’s why we get 100fps on every pc
Replying to @Hillsguy2
Interesting!