Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix DoF's dependency on resolution #57210

Closed
wants to merge 1 commit into from
Closed

Fix DoF's dependency on resolution #57210

wants to merge 1 commit into from

Conversation

ghost
Copy link

@ghost ghost commented Jan 25, 2022

fixes #56911

This has no impact on how the glow effect scales with the resolution, but I couldn't be bothered to do a different recording.

demo-.6.mp4

@ghost ghost self-requested a review as a code owner January 25, 2022 16:59
@Chaosus Chaosus added this to the 4.0 milestone Jan 25, 2022
@clayjohn
Copy link
Member

This looks fine to me, but I am worried about the performance impact, especially when using the circular bokeh mode.

Can you test circular bokeh on both low res, HD, and 4K?

Or maybe @Calinou is able to test on HD and 4K?

@@ -2362,6 +2362,8 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende

// @TODO IMPLEMENT MULTIVIEW, all effects need to support stereo buffers or effects are only applied to the left eye

float resolution_factor = p_render_data->cam_vaspect ? (float(rb->internal_width) / 1920.0) : (float(rb->internal_height) / 1080.0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does 1920x1080 correspond to something specific in the renderer? It seems a bit weird to see this hardcoded, wouldn't it need to reflect the actual game viewport size?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see this was discussed in #56911 (comment). A comment to justify the hardcoded reference size would be useful.

This comment was marked as outdated.

@ghost
Copy link
Author

ghost commented Jan 25, 2022

@clayjohn I tested with Circular and High Quality Bokeh.

With this patch:

Scaling FPS
0.5 scaling (960x540) 480
1.0 scaling (1920x1080) 195
2.0 scaling (3840x2160): 18

Without this patch:

Scaling FPS
0.5 scaling (960x540) 395
1.0 scaling (1920x1080) 195
2.0 scaling (3840x2160): 55

Picking a higher reference resolution would most likely improve the situation for 4k as well, but I'm not sure that's the solution or if one is required. Any suggestions?

@clayjohn
Copy link
Member

Picking a higher reference resolution would most likely improve the situation for 4k as well, but I'm not sure that's the solution or if one is required. Any suggestions?

Picking a higher reference resolution is the same as decreasing the fixed 64.0 multiplier or reducing the default bokeh size (which was likely chosen for artistic reasons rather than performance reasons).

I see two solutions and I am torn between the two:

  1. Go with this PR and have a warning in the documentation that performance will scale with resolution, so at high resolutions, you may want to reduce bokeh size proportionately.
  2. Don't merge this PR and have a warning saying that Bokeh size is fixed at 64 pixels * user_specified_size and users should scale this with resolution if they want consistent results.

Number 1 is nice, because we want the default to be "just works". That being said the performance cost is pretty hard to swallow. The end result would be "it just works*" (* but runs too slow to use).

Number 2 is better for performance and for users who don't care about blur amount as much.

Can you do another table like the above, but for Box blur and hexagon blur? They both should scale much better with resolution. If the difference isn't as bad with them, then I lean towards 1.

@Calinou
Copy link
Member

Calinou commented Jan 25, 2022

Can you do another table like the above, but for Box blur and hexagon blur? They both should scale much better with resolution. If the difference isn't as bad with them, then I lean towards 1.

I feel we should change the circle bokeh shape to not have performance that depends on DoF amount, even if this means it'll look worse at higher resolutions. This amount-dependent caveat is just too bothersome for game developers to handle, especially if they want to expose circle bokeh as an opt-in setting for those with fast GPUs (and keep box/hexagon shape by default). It can also cause unexpected performance dips when animating the DoF amount at run-time.

I remember discussing this with @lyuma in #rendering on the Godot Contributors Chat, but I can't find the messages in question right now. They posted a code sample which made circle DoF have the same performance regardless of the DoF amount (at the cost of visual quality at high amounts).

I would really prefer not to have resolution-dependent DoF as the default, as many developers don't test their games on high-resolution displays (since they don't own the required hardware in the first place). Also, resolution-dependent DoF can give some players an advantage if the blur effect is intended to obstruct something the player shouldn't see.

If anyone wants to work on this, I made a testing project: test_depth_of_field_circle.zip

@ghost
Copy link
Author

ghost commented Jan 26, 2022

I wrote a little Python function, in order to understand how many iterations are being made for the circular bokeh inside this for loop:

def iterations(blur_scale, blur_size):
  radius = blur_scale
  i = 0
  while radius < blur_size:
    radius += blur_scale / radius
    # print(radius)
    i += 1
  return i

blur_scale = one of [8.0, 4.0, 1.0, 0.5] - it represents the blur quality setting, from very low quality to high quality

blur_size = dof_blur_amount (from the camera) * 64.0 (hardcoded multiplier) * resolution_factor (from this PR)


And here's some results:

blur_scale blur_size iterations
8 (VLQ) 0.2 * 64 * 1.0 6
4 (LQ) 0.2 * 64 * 1.0 18
1 (MQ) 0.2 * 64 * 1.0 80
0.5 (HQ) 0.2 * 64 * 1.0 162
blur_scale blur_size iterations
8 (VLQ) 0.2 * 64 * 2.0 37
4 (LQ) 0.2 * 64 * 2.0 79
1 (MQ) 0.2 * 64 * 2.0 326
0.5 (HQ) 0.2 * 64 * 2.0 653
blur_scale blur_size iterations
0.5 (HQ) 0.1 * 64 * 1.0 39
0.5 (HQ) 0.2 * 64 * 1.0 162
0.5 (HQ) 0.3 * 64 * 1.0 367
0.5 (HQ) 0.4 * 64 * 1.0 653
0.5 (HQ) 0.5 * 64 * 1.0 1022

The increase in iterations looks pretty steep when cycling between DoF amount and qualities.
As far as I can tell these numbers (also) don't depend on the viewport's resolution, and maybe they should?

@clayjohn
Copy link
Member

The increase in iterations looks pretty steep when cycling between DoF amount and qualities.
As far as I can tell these numbers (also) don't depend on the viewport's resolution, and maybe they should?

Your resolution multiplier would make this dependent on resolution. You can see the default setting is to blur over 64 pixels * dof_amount.

If we wanted to keep the cost the same as screen size changed we could scale both the blur_scale and blur_size This would keep the size and performance constant, but quality would suffer with a change in resolution.

@ghost
Copy link
Author

ghost commented Jan 26, 2022

Your resolution multiplier would make this dependent on resolution. You can see the default setting is to blur over 64 pixels * dof_amount.

Yes, I was thinking about blur_scale, but wasn't obvious from what I wrote.

If we wanted to keep the cost the same as screen size changed we could scale both the blur_scale and blur_size This would keep the size and performance constant, but quality would suffer with a change in resolution.

I'll try to find a sweet spot where quality doesn't visibly chang, but performance improves.

@ghost
Copy link
Author

ghost commented Jan 29, 2022

As promised, I've been working on improving the performance of the circle blur. Here's some screenshots to compare performance and looks:

master optimised
dof_master_circle_hq_09 dof_branchv6_circle_hq_1

I've still got a few things to sort out, like improving the quality and performance of the near blur, maybe see if I can make the whole thing resemble the unoptimised effect better... and tidy up the code, although it's mostly just some small changes inside the shader code.

I'm thinking of introducing these tweaks as a new DoF mode and call it "Circle Optimised" (?). So whoever wants to use the high quality, uncompromising classic "Circle" mode can still do so, but I think that one is more suitable for offline rendering as it stands.


Even if the optimized DoF performs well regardless of blur_size, scaling up the resolution increases both the pixel count and the blur_size (as of this PR)... so performance will degrade quicker when scaling, no matter how optimized the effect is.

That means I might still have to add a setting, for a finer control of the decrease in quality as resolution goes up.

I could also just pick a default resolution-quality factor that's good enough, and call it a day.


Here's a recording as well:

dof-optimized.mp4

@Calinou
Copy link
Member

Calinou commented Jan 29, 2022

The new circle mode looks great! Nice work 🙂

So whoever wants to use the high quality, uncompromising classic "Circle" mode can still do so, but I think that one is more suitable for offline rendering as it stands.

I think your new mode can replace the existing Circle mode, as offline rendering with Godot is considered to be a corner case. It probably doesn't warrant having entire rendering modes on its own. Pushing up all other settings (such as shadow quality and DoF quality will usually make rendering look good enough (and be slow enough) already.

@Calinou
Copy link
Member

Calinou commented Mar 18, 2022

@ceLoFaN Could you open a pull request with the optimized circle DoF (assuming it's this branch)? Thanks in advance 🙂

@ghost
Copy link
Author

ghost commented Mar 22, 2022

Sorry for the long silence, but I've been dealing with various health issues for the past 5 weeks or so.

Here's the branch if anybody wants to tidy it up or give it a spin: https://github.com/godotengine/godot/compare/master...ceLoFaN:improve-dof?expand=1

Some numbers might need more tweaking to get the before advertised FPS, but the good news is I fixed 2 bugs that resulted in visual artifacts at various DOF settings (one was an implementation mistake, and one was a scaling mistake that happened on odd numbered resolution, as in 1919x1079), and it resembles the original DOF better.

I was also messing with a denoising step at the time, which you guys might not like as much, but to me looked somewhat promising.

Also, servers/rendering/renderer_rd/shaders/bokeh_dof_raster.glsl is not updated with the changes.

Also, the other DOF variants (box, hex...) might need to be adjusted because of the scaling bug-fix... not sure haven't tested.

Unfortunately, I don't think I'll be able to resume work on this for the forseable future, but I pushed what I had at the time on my working branch.

@clayjohn
Copy link
Member

Bumping the milestone to 4.x. @ceLoFaN's work on an optimized circle mode is very interesting and we should properly evaluate whether it can replace the current circle mode or be added as another option.

At this point, I don't think we should decouple resolution from DoF until we have a good handle on the resulting performance issues. So this is 4.x work.

@ghost ghost closed this by deleting the head repository Oct 13, 2023
@AThousandShips AThousandShips removed this from the 4.x milestone Oct 13, 2023
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Vulkan: CameraAttributes depth of field amount is resolution-dependent
5 participants