View Issue Details

IDProjectCategoryView StatusLast Update
0005850The Dark ModGraphicspublic19.11.2022 11:10
Reporterstgatilov Assigned Tostgatilov  
Status resolvedResolutionfixed 
Product VersionTDM 2.10 
Target VersionTDM 2.11Fixed in VersionTDM 2.11 
Summary0005850: Volumetric lights: render to texture then blur
DescriptionThe reason why original volumetric lights achieved good performance with plausible quality is dithering.
While they look nice overall, in some cases (especially with shadows) the dithering becomes apparent.

Ideally, we should render each volumetric light to off-screen framebuffer, then blend it on top of the main framebuffer.
This allows for several things:
1) Volumetric light can go through low-pass filter (e.g. blur) to make dithering less noticeable.
2) Volumetric light can be rendered with lower resolution, allowing us to use more samples (e.g. 2x lower resolution means 4x more samples).

Of course, the operations of the new framebuffer should only affect a subrectangle defined by light scissor.
Make sure we don't blur or blit the whole framebuffer for small lights, otherwise there will be huge penalty for having many small lights on screen.
TagsNo tags attached.


related to 0005816 resolvedduzenko Volumetric lights (aka "god rays") 




31.10.2022 20:03

administrator   ~0015384

I started working on this, and realized that the stuff proposed here is not entirely straight-forward.
Yes, the volumetric light itself is often low-frequency, but there are edges of light frustum, and edges of geometry (via depth buffer).
The blur/lowres code here should take depth discontinuity into account.

I looked a few articles on the internet:

Apparently, people usually implement volumetric light with both techniques included:
  * raymarching on downscaled FBO (1/2 size)
  * dithering: either Bayer matrix or blue noise
  1) render raymarched volumetric lights with dithering into half-size FBO
  2) depth-aware blur of half-size FBO (apparently keeping half-size)
  3) depth-aware upsampling and compositing

While depth-aware ("bilateral") blur and upsampling are standard techniques today, they are many implementation details which might differ.
I especially like the last link in this regard:

The important details are:
1) When computing downscaled data, we usually consider a point in the middle of 2x2 pixel block...
    However we should not just take average depth of 4 pixels: better take nearest depth.
2) When doing the blur, we probably should not separate horizontal/vertical passes, since depth-aware blur is not separable =(
3) When upscaling the data, we take four 2x2 blocks as data sources.
  Then we do bilinear interpolation of their values, but with additional weights deduced from the difference between fullres depth and the depth used during downscaled rendering.
  Unfortunately, all four weights might be close to zero, so if total weight is low, then probably just take closest 2x2 block as single source?...

Most likely, I will have to make half-size FBO for depth buffer too.

So the plan is:
1) Move code to separate class.
2) Add full-size FBO and separate raymarching from compositing.
3) Try to blur FBO (will need another FBO for ping-pong).
4) Try to make FBO half-res, with all the downscaling/upscaling issues.


05.11.2022 18:26

administrator   ~0015390

Committed new implementation in svn rev 10146.

The implementation is exactly as described above:
  8 samples per pixel
  with Bayer dithering
  depth-aware blur
  depth-aware upsampling

* The blur is separable (i.e. separate horizontal and vertical passes).
It is not equivalent to single-pass Gauss blur, but it blurs pretty well and it much cheaper.
* Speaking of depth downsampling, I did not do anything special.
Apparently, filtering is set to "nearest" on depth texture, so when I fetch at the middle of 2x2 block, some pixel is selected automatically.
* The problem of zero total weight is alleviated by selecting between bilinear filtering and taking nearest sample.

And there is a bunch of cvars now.
Listing them with their current defaults and values to achieve old behavior:
  r_volumetricSamples 8
  r_volumetricDither 1
  r_volumetricBlur now: 2 old: 0
  r_volumetricLowres now: 1 old: 0
So if you set the last two to 0, FBOs will NOT be used, and you'll get the exact picture from 2.10.


05.11.2022 18:37

administrator   ~0015391

The performance is better in general, dithering pattern is gone.

Some artifacts are visible occasionally:

1) If I look through volumetric light at a far point of ideally horizontal planar ground, I see some bits of noise.
That's because depth-aware blur does not blur the noise perfectly.
It cannot do that because the change in viewZ is very high when stepping up in blur shader --- greater than depth tolerance.
I don't think I can fix it reliably: it's better to have some mess at far distance, then blurred edges of objects at near distance.

2) If you have a cubic volumetric light with constant light intensity, and look approximately along its face, then you see some low-resolution aliasing.
I could not find a satisfactory solution against it: that's the case when volumetric light becomes non-smooth despite smooth depth, so blurring is not enough to hide low-resolution mess.

3) The effect is still not friendly with multisampling: if AA is on, then you can see 1-pixel wide dotted lines at the edge of objects.
Or if you don't, then you can see the aliasing on the edge as if AA was off.
The reason for this is that the effect totally ignores multisampling.

In principle, the issue with multisampling can be fixed the following way:
  1) Make multisampled depth texture available in volumetric light compositing shader.
  2) Use gl_SampleID (needs GL4.0, so check for extension) to force compositing shader to run for every sample, instead of for every pixel.
  3) For each sample, fetch its depth and use it in depth-aware upsampling.


05.11.2022 18:54

developer   ~0015392

The aliasing is really bad on anything in front of the effect.


05.11.2022 18:55

developer   ~0015393

It's very noticeable in motion too.


05.11.2022 19:37

administrator   ~0015394

I'm afraid you'll have to record a short video and share it as file.
Otherwise it is hard to understand which issue you are talking about...


05.11.2022 19:58

developer   ~0015395

As the Zombie walks in through the door, he's outlined by the volumetric light. You can see pixelation all around him.


05.11.2022 22:38

administrator   ~0015396

I noticed bad artifacts of depth-aware blur/upsampling, which resulted from round-off errors.
That's because I sampled depth texture in the center of low-res pixel, which is exactly in-between 4 high-res texels... meaning that it was uncertain which of them were selected.
Now I have added a half-pixel shift, and the issue is gone.

That's svn rev 10147.


06.11.2022 01:27

developer   ~0015397

New issue, the artifacts are now showing up with r_volumetricLowres 0, but go away when set to 1.

r_volumetricLowres 0

r_volumetricLowres 1


06.11.2022 06:37

administrator   ~0015399

Yeah, subpixel shift should not be applied with full-res effect.
Fixed in svn rev 10148.


10.11.2022 22:26

administrator   ~0015414

Some more changes:
  r10151 Cap depth/distance by backfaces of frustum.
  r10152 Don't forget to shutdown volumetric singleton, otherwise it crashes on first use after engine reload.
  r10156 Disable volumetric lights ins subviews.

The point 1 of the above list of artefacts is fixed, since now I cap depth values by depth of frustum's backfaces.

I'd say this issue is finished.


18.11.2022 21:24

administrator   ~0015451

More improvements from Daft Mugi's feedback:
  r10161 Use FBO of format GL_R11F_G11F_B10F instead of GL_RGBA8.
  r10162 Fixed bug that depthToZ returned -infty instead of +infty for depth = 1.
  r10163 Increased r_volumetricSamples from 8 to 24.


19.11.2022 11:10

administrator   ~0015454

More fixes due to Daft Mugi feedback.

Fixing shadows of portal sky pyramids in Hazard Pay:
  r10164 Never force huge lights to shadow maps, even if they have volumetrics.
  r10165 Force-disable volumetrics in subviews: do it early in frontend, not in backend.
Allow players to tweak volumetrics if they so much want it:
  r10166 Added r_volumetricDustMultiplier cvar that allows player to tweak strength of volumetric to his liking.

Issue History

Date Modified Username Field Change
21.12.2021 17:16 stgatilov New Issue
21.12.2021 17:17 stgatilov Relationship added related to 0005816
31.10.2022 19:38 stgatilov Assigned To => stgatilov
31.10.2022 19:38 stgatilov Status new => assigned
31.10.2022 20:03 stgatilov Note Added: 0015384
05.11.2022 18:26 stgatilov Note Added: 0015390
05.11.2022 18:37 stgatilov Note Added: 0015391
05.11.2022 18:54 AluminumHaste Note Added: 0015392
05.11.2022 18:54 AluminumHaste File Added: hazard (2022-11-05 14-52-42) (3955.46 1357.27 -83.37).png
05.11.2022 18:54 AluminumHaste File Added: hazard (2022-11-05 14-52-40) (3931.78 1358.65 -80.32).png
05.11.2022 18:54 AluminumHaste File Added: hazard (2022-11-05 14-52-38) (3930.18 1358.8 -114.3).png
05.11.2022 18:55 AluminumHaste Note Added: 0015393
05.11.2022 19:37 stgatilov Note Added: 0015394
05.11.2022 19:58 AluminumHaste Note Added: 0015395
05.11.2022 22:38 stgatilov Note Added: 0015396
06.11.2022 01:27 AluminumHaste Note Added: 0015397
06.11.2022 06:37 stgatilov Note Added: 0015399
10.11.2022 22:26 stgatilov Note Added: 0015414
10.11.2022 22:26 stgatilov Status assigned => resolved
10.11.2022 22:26 stgatilov Resolution open => fixed
10.11.2022 22:26 stgatilov Fixed in Version => TDM 2.11
18.11.2022 21:24 stgatilov Note Added: 0015451
19.11.2022 11:10 stgatilov Note Added: 0015454