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

[Merged by Bors] - Add FXAA postprocessing #6393

Closed
wants to merge 19 commits into from

Conversation

DGriffin91
Copy link
Contributor

Objective

  • Add post processing passes for FXAA (Fast Approximate Anti-Aliasing)
  • Add example comparing MSAA and FXAA

Solution

When the FXAA plugin is added, passes for FXAA are inserted between the main pass and the tonemapping pass. Supports using either HDR or LDR output from the main pass.


Changelog

  • Add a new FXAANode that runs after the main pass when the FXAA plugin is added.

@alice-i-cecile alice-i-cecile added C-Enhancement A new feature A-Rendering Drawing game state to the screen labels Oct 29, 2022
Copy link
Member

@cart cart left a comment

Choose a reason for hiding this comment

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

Great work!

I think the blit / intermediate tonemapping stuff can / should be removed in favor of running this after tonemapping (and thus, after effects like bloom). This cuts down on the complexity / work being done. This is how Unity and Wicked Engine do it, and is also how I generally see FXAA being used in the wild (it is often applied in userspace after all engine rendering has finished).

I think we can also simplify the FXAA pipeline generation stuff using specialization.

This should also be ported to #6415, which I made in direct response to this PR's intermediate texture creation. See the description for details.

I've addressed all of these things on my local branch. I'll push the changes after #6415 is merged.

examples/wasm/assets Outdated Show resolved Hide resolved
crates/bevy_core_pipeline/src/fxaa/mod.rs Outdated Show resolved Hide resolved
examples/3d/fxaa.rs Outdated Show resolved Hide resolved
Comment on lines +74 to +75
let source = post_process.source;
let destination = post_process.destination;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason for this or is it just to have shorter variable names?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As far as I understand, yes.

Copy link
Member

Choose a reason for hiding this comment

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

Yup just that

Copy link
Contributor

@IceSentry IceSentry left a comment

Choose a reason for hiding this comment

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

A couple of general questions and I'm not familiar with the math, so I can't comment on that part but overall this looks great.

@DGriffin91
Copy link
Contributor Author

Something a bit odd: the difference between HDR vs LDR is now greater than it was before, with the old to_ldr & blit passes (97251f4). When set to ultra, may of the colored squares now still show aliasing only when using HDR.

(View at original size or larger to see aliasing)

Before without hdr (97251f4)
before without hdr

Before with hdr (97251f4)
before with hdr

After without hdr (2bd5fd8)
after without hdr

After with hdr (2bd5fd8)
after with hdr

@cart
Copy link
Member

cart commented Nov 1, 2022

Hmm nice catch. I can repro on my machine.

The old non-hdr pipeline looks like this:

main_pass_with_reinhard_tonemapping(Rgba8UnormSrgb) ->
Blit(RgbaUnormSrgb->Rgba8UnormSrgb) ->
FXAA(Rgba8UnormSrgb->Rgb8UnormSrgb)

FXAA's inputs are "reinhard tonemapped Rgba8UnormSrgb"
New non-hdr pipeline is exactly the same, but without the blit

The old hdr pipeline looked like this:

main_pass_without_tonemapping(Rgba16Float) ->
to_ldr_with_reversible_tonemapping(Rgba16Float->Rgba16Float) ->
FXAA_then_reversed_reversible_tonemap(Rgba16Float->Rgba16Float) ->
reinhard_tonemap_to_ldr(Rgba16Float->Rgba8UnormSrgb)

FXAA's inputs are "reversible-tonemapped Rgba16Float"

The new hdr pipeline looks like this:

main_pass_without_tonemapping(Rgba16Float) ->
reinhard_tonemapping (Rgba16Float -> Rgba16Float) -> 
FXAA(Rgba16Float->Rgba16Float)

FXAA's inputs are "reinhard tonemapped Rgba16Float"
It could be that this combination of things is what makes this different.

Worth poking around a bit.

@cart
Copy link
Member

cart commented Nov 1, 2022

Lowering EDGE_THRESH_ULTRA to 0.043 does bring "new hdr" more in-line with the old results. But it does feel like we should be able to use the same threshold values between hdr and ldr pipelines, given that they should be the "same reinhard-mapped ldr colorspace" at this point in the pipeline.

@cart
Copy link
Member

cart commented Nov 1, 2022

As this has to do with the threshold, here are the lumaRange values visualized:

Old - LDR
Screenshot from 2022-11-01 01-47-08-old-no-hdr

Old - HDR
Screenshot from 2022-11-01 01-47-30-old-hdr

New - LDR
Screenshot from 2022-11-01 01-43-53-new-no-hdr

New - HDR
Screenshot from 2022-11-01 01-44-47-new-hdr

@cart
Copy link
Member

cart commented Nov 1, 2022

Notably, the "new hdr" image does have lower lumaRange values in the cube areas that have more aliasing, so that makes sense.
However interestingly in general the "old hdr" pipeline seems like the biggest outlier when it comes to "average lumaRange".

@cart
Copy link
Member

cart commented Nov 1, 2022

Ok after much investigation, we've come to the following conclusions:

  1. There are background color differences between HDR and LDR. This is because when we tonemap in the LDR main pass / pbr shader, we don't apply tonemapping to the clear color, but when we tonemap in a post processing step (the current HDR pipeline), we do. This could be fixed by tonemapping the clear color on the CPU for LDR or by rendering the background color in a shader (making it not a "clear color" anymore).
  2. There are color differences in the lens of the flight helmet. This is because we are tonemapping each transparent fragment in the LDR main pass, but we are tonemapping the final composited pixel in the HDR post processing tonemapping. HDR is "correct" here. The incorrectness in main-pass tonemapping is inherent to the approach / not really solvable.
  3. The differences in lumaRange between HDR and LDR seem to be precision issues between the HDR and LDR targets. Things like moving tonemapping to the main pass for HDR and using a non-srgb target in LDR did not resolve the issue. We will just need to accept this and provide additional configuration levels for FXAA that allow HDR FXAA to be tuned appropriately.

@cart
Copy link
Member

cart commented Nov 1, 2022

There was also a bug in how we applied tonemapping in the main pass (we skipped it in some cases). I have fixed it in the commit above.

@cart
Copy link
Member

cart commented Nov 2, 2022

bors r+

bors bot pushed a commit that referenced this pull request Nov 2, 2022
# Objective

- Add post processing passes for FXAA (Fast Approximate Anti-Aliasing)
- Add example comparing MSAA and FXAA

## Solution

When the FXAA plugin is added, passes for FXAA are inserted between the main pass and the tonemapping pass. Supports using either HDR or LDR output from the main pass.

---

## Changelog

- Add a new FXAANode that runs after the main pass when the FXAA plugin is added.

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
@bors bors bot changed the title Add FXAA postprocessing [Merged by Bors] - Add FXAA postprocessing Nov 2, 2022
@bors bors bot closed this Nov 2, 2022
ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Feb 1, 2023
# Objective

- Add post processing passes for FXAA (Fast Approximate Anti-Aliasing)
- Add example comparing MSAA and FXAA

## Solution

When the FXAA plugin is added, passes for FXAA are inserted between the main pass and the tonemapping pass. Supports using either HDR or LDR output from the main pass.

---

## Changelog

- Add a new FXAANode that runs after the main pass when the FXAA plugin is added.

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen C-Enhancement A new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants