godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.16k stars 97 forks source link

Integrate sub-pixel morphological antialiasing (SMAA) in the Vulkan renderer #2779

Open Calinou opened 3 years ago

Calinou commented 3 years ago

Related to https://github.com/godotengine/godot-proposals/issues/3401.

Describe the project you are working on

The Godot editor :slightly_smiling_face:

Describe the problem or limitation you are having in your project

Right now, we have MSAA and FXAA available in both 3.x and master. These algorithms serve their intended purposes, but each of them has their own limitations:

It's possible to use both MSAA and FXAA at the same time, but this has a significant cost and it won't improve the image's sharpness after it has been reduced by FXAA.

It's great that MSAA is still supported in master (thanks to the clustered forward renderer), but we have to admit that it's difficult to use in production with today's shader complexity. Therefore, this makes MSAA mostly suited to games that use few visual effects, which generally implies a stylized art direction.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Sub-pixel morphological antialiasing (SMAA) has been around since 2011 and is now a proven post-processing-based antialiasing algorithm. It's still used in a lot of AAA games.

Performance-wise, SMAA is more expensive than FXAA, but it does a good job at antialiasing despite introducing less blurriness. Either way, SMAA is likely to be less expensive than even 2× MSAA on the Vulkan renderer (despite providing better edge smoothing overall).

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

One downside of SMAA is that it's notoriously difficult to implement. Not only it's a multi-pass algorithm (unlike FXAA which is single-pass), there are also many quality settings to tinker with.

We can probably go with the recommended SMAA settings (luma-based edge detection), and only see if there are real benefits to exposing quality knobs in the project settings (such as changing the edge detection algorithm).

SMAA also offers an optional temporal component, but that comes with added complexity and motion trails commonly associated with temporal antialiasing algorithms. Therefore, I suggest we leave out the temporal antialiasing part of SMAA and focus on spatial-only SMAA (also called SMAA 1×). SMAA won't look as smooth without this temporal component, but SMAA still looks better than FXAA without it.

I've looked around a bit and couldn't figure out how to add a multi-pass post processing shader in Godot's GLSL core, so feel free to give it a try.

Question: Can this be implemented in 3.x? I haven't seen any implementation of SMAA on OpenGL ES 3.0 (and even less OpenGL ES 2.0), so probably not. Edit: It's possible to implement SMAA in WebGL 2.0 (and therefore OpenGL ES 3.0): https://github.com/dmnsgn/glsl-smaa

If this enhancement will not be used often, can it be worked around with a few lines of script?

Since real-time multi-pass shaders aren't possible in "userland" Godot yet, no.

Is there a reason why this should be core and not an add-on in the asset library?

See above.

clayjohn commented 3 years ago

For reference, the original SMAA code can be found here and it is MIT licenced.

LiveTrower commented 3 years ago

I found this: https://github.com/dmnsgn/glsl-smaa, i hope it helps.

Calinou commented 3 years ago

This porting work may also be useful as a reference: https://github.com/libretro/slang-shaders/pull/189

jntesteves commented 3 years ago

This porting work may also be useful as a reference: libretro/slang-shaders#189

Hey, if you want to take any reference from my work there, please check the aftermath: libretro/slang-shaders#192

I can't agree with the docs on luma by default. I tested it extensively and color based edge detection always gave me better results, with less aliasing but not blurrier. In the end, I exposed every config knob, so I could more easily tweak settings at runtime. Tweaking it for your content is worthwhile, this AA is powerful when properly setup.

SMAA_PRESET_ULTRA + SMAAColorEdgeDetectionPS seemed like a good default to me. I increased AA strength a nod (SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR 2.5) where I knew there would be sharpening in a following pass, like SMAA+FSR.

My code is in the public domain, no restrictions apply. Feel free to copy anything.

Calinou commented 3 years ago

I've started work on integrating SMAA: https://github.com/Calinou/godot/tree/add-smaa-antialiasing

It's far from functional yet, but feel free to take a look nonetheless.

Lasuch69 commented 2 years ago

Is there any update on this?

Calinou commented 2 years ago

Is there any update on this?

I haven't managed to get it working, as I have very little time to work on this.

Note that Godot 4 now offers temporal antialiasing, which you could combine with sharpening to counteract the added blurriness. This would still result in some amount of visible ghosting depending on the scene, but TAA handles specular and shader-induced aliasing much better than SMAA (which barely has any positive effect on this kind of aliasing).

TAA and FXAA sharpness can also be improved by adjusting mipmap LOD bias automatically.

I still think supporting SMAA is valuable for at least 2 scenarios:

jntesteves commented 2 years ago

I don't have any stake in Godot at the moment, so my opinion might not be too relevant, but I think working on the multi-pass shaders proposal mentioned in the description is a more worthwhile use of time. With that, anyone could easily do SMAA or whatever other post-process effects they want, not limited by what the engine offers.

Edit: Maybe these kinds of shaders should be on the Asset Library.

Jamsers commented 1 year ago

CMAA2 may be a great alternative to consider, it's been used to great effect in the recently released Counter Strike 2 and seems to work well as an MSAAesque cheap post process fallback.

The original repo published by Intel: https://github.com/GameTechDev/CMAA2

Intel's article on CMAA2 An article describing a hybrid CMAA implementation for mobile

A ReShade implementation: https://github.com/LordOfLunacy/Insane-Shaders/blob/master/Shaders/CMAA_2.fx

jams3223 commented 1 year ago

How is this coming along? I was going to open a proposal until I saw this one. SMAA is the perfect middle ground in terms of performance, quality, and artifacts.

Q: Describe the project you are working on A: 3D games that make use of realistic art styles and complex shapes

Q: Describe the problem or limitation you are having in your project A: TAA tends to create ghosting artifacts while in motion, and while TAA is better at removing aliasing than SMAA, it still does a good job without having these issues; it's a good middle ground between TAA and FXAA. TAA is more resource-intensive and prone to artifacts, while FXAA is less effective.

Q: Describe the feature / enhancement and how it helps to overcome the problem or limitation A: Add it to the list of already-available anti-aliasing algorithms.

Q: If this enhancement will not be used often, can it be worked around with a few lines of script? A: No, it can't be used with a few lines of code; it needs to be implemented into the core engine.

Q: Is there a reason why this should be core and not an add-on in the asset library? A: It sits right along with the other anti-aliasing methods that Godot ships with, so it helps extend the user's preferred choice and ensure a balanced level of quality.

Calinou commented 1 year ago

How is this coming along? I was going to open a proposal until I saw this one. SMAA is the perfect middle ground in terms of performance, quality, and artifacts.

SMAA is generally considered to be a stale approach by 2023 standards, so I wouldn't hold my hopes for it being added as a core feature (in the age of ever-improving TAA solutions). However, the rendering engine will eventually be made more flexible so that SMAA can be implemented by an add-on.

Modern games are often full of geometric and specular detail that SMAA can't do anything about. The only real use case I can see for SMAA nowadays is antialiasing an image when you have no access to motion vectors (such as running old games, antialiasing screenshots, etc). Similar concerns apply to other techniques like CMAA.

Being able to use TAA + SMAA at the same time isn't so important anymore, now that we have access to FSR2 at native resolution. This provides high-quality antialiasing with a sharper result compared to native TAA.

TAA is pending optimizations in the motion vector generation part, which will make it significantly less demanding.

Jamsers commented 1 year ago

Modern games are often full of geometric and specular detail that SMAA can't do anything about

That's fine - the users wanting to use SMAA aren't expecting it to match or even come close to the antialiasing capability of TAA - the point is to get the best possible antialiasing possible today that isn't TAA (due to ghosting and artifacting that will never be solved no matter how improved TAA gets) or MSAA (due to prohibitive performance cost)

SMAA is generally considered to be a stale approach by 2023 standards

Irrelevant. Progress and development on non-temporal post process antialiasing methods has practically halted, so unless the Godot team is planning to create a bespoke new technique, SMAA is still the best there is. (again, if you don't want TAA or MSAA)

If anything, FXAA is the stale, outdated, irrelevant technique - why is that still in core?

jams3223 commented 1 year ago

I have tested the anti-aliasing algorithm with every kind of game art style, and I can say that it all depends on the art style or visual style. Godot will benefit by giving people choices in how they want to customize their game.

FXAA: (+) Better with cel-shaded and anime art styles (-) Lower Quality (+) Better Performance

MSAA: (+) Better with realistic art styles (+) Higher Quality (-) Lower Performance

TAA: (+) Better with realistic art styles (+) Higher Quality (+) Balanced Performance (-) Visual Artifact

SMAA: (+) Better with realistic, anime and voxel art styles (+) Balanced Quality (+) Balanced Performance

mrjustaguy commented 11 months ago

One thing I see forgotten in here is the fact that SMAA can optionally be temporal itself, also known as SMAAT2x

Jamsers commented 11 months ago

I think temporal SMAA is actually stale, since updated TAA and TAAU (FSR 2) techniques have largely superseded any of the benefits temporal SMAA can offer today.

But the single pass SMAA stays relevant and best in class due to the lack of development on non-temporal post process antialiasing methods.

mrjustaguy commented 11 months ago

SMAAT2x still beats our TAA implementation in quality and likely even performance (though that is largely because of just how totally borked it is) and FSR2 is really expensive at native res, though I don't know the diff between SMAAT2x and FSR2

Jamsers commented 11 months ago

Absolutely, but as you say, that's a testament to how terrible Godot's TAA implementation is, rather than SMAA T2x being the way to go. And the current FSR 2 implementation has a disproportionately high performance cost - it's damn near 12% of GPU time on a relatively heavy and complex scene - so some optimization work is definitely due there.

mrjustaguy commented 11 months ago

FSR2 performance matches what AMD states for it's Performance Costs, and it's really designed for Upscaling, where you're rendering at a lower internal resolution (reducing the FSR2 cost) and Upscaling, improving the performance due to significantly less shading per frame

Xynonners commented 9 months ago

Hey all,

just dropping in to add that it is actually possible to implement / port reshade AA to gdshader.

here is my LXAA port: https://gist.github.com/Xynonners/6e50a27d562829469281be45b039ec93 and here is HHAA (a weird mishmash bespoke algorithm I made for 3D): https://gist.github.com/Xynonners/ddf30a5215a59db5690f6420621f0623

someone smarter than me could probably do a CMAA2 port if they wanted to.

pretty tired of waiting for AA from godot, considering that FXAA is stale, TAA is broken (motion smear).

jams3223 commented 9 months ago

Hey all,

just dropping in to add that it is actually possible to implement / port reshade AA to gdshader.

here is my LXAA port: https://gist.github.com/Xynonners/6e50a27d562829469281be45b039ec93 and here is HHAA (a weird mishmash bespoke algorithm I made for 3D): https://gist.github.com/Xynonners/ddf30a5215a59db5690f6420621f0623

someone smarter than me could probably do a CMAA2 port if they wanted to.

pretty tired of waiting for AA from godot, considering that FXAA is stale, TAA is broken (motion smear).

I've never heard of HHAA, did you make it yourself?

Xynonners commented 9 months ago

Hey all, just dropping in to add that it is actually possible to implement / port reshade AA to gdshader. here is my LXAA port: https://gist.github.com/Xynonners/6e50a27d562829469281be45b039ec93 and here is HHAA (a weird mishmash bespoke algorithm I made for 3D): https://gist.github.com/Xynonners/ddf30a5215a59db5690f6420621f0623 someone smarter than me could probably do a CMAA2 port if they wanted to. pretty tired of waiting for AA from godot, considering that FXAA is stale, TAA is broken (motion smear).

I've never heard of HHAA, did you make it yourself?

Yup, the idea was to be more aggressive than LXAA (which tends to be extremely conservative for the sake of anti-blur), but less blurry than the blur-fest that is FXAA. HHAA is a weird hybrid/combined antialiasing shader, but imo it works pretty well (I do believe it could still be more aggressive - though I don't think I'm smart enough to make something better than this).

Because of its completely custom nature though, it may have a sizeable performance impact, though I roughly tested it and it seems to be fine. Also may have bugs in implementation.

Jamsers commented 9 months ago

It produces pretty SMAAesque results to my eyes when I tested it on Bistro-Demo-Tweaked. Any chance you could port CeeJayDK's SMAA? 👉👈🥺

I tried it myself but I have zero shader knowledge and only got as far as porting the UI variables 😅

Beanibirb commented 7 months ago

Hey all,

just dropping in to add that it is actually possible to implement / port reshade AA to gdshader.

here is my LXAA port: https://gist.github.com/Xynonners/6e50a27d562829469281be45b039ec93 and here is HHAA (a weird mishmash bespoke algorithm I made for 3D): https://gist.github.com/Xynonners/ddf30a5215a59db5690f6420621f0623

someone smarter than me could probably do a CMAA2 port if they wanted to.

pretty tired of waiting for AA from godot, considering that FXAA is stale, TAA is broken (motion smear).

Inexperienced with setting up shaders for Godot here, how would one implement either of these in a 3D template?

mrjustaguy commented 7 months ago

See https://docs.godotengine.org/en/stable/tutorials/shaders/custom_postprocessing.html

Beanibirb commented 7 months ago

Hey all,

just dropping in to add that it is actually possible to implement / port reshade AA to gdshader.

here is my LXAA port: https://gist.github.com/Xynonners/6e50a27d562829469281be45b039ec93 and here is HHAA (a weird mishmash bespoke algorithm I made for 3D): https://gist.github.com/Xynonners/ddf30a5215a59db5690f6420621f0623

someone smarter than me could probably do a CMAA2 port if they wanted to.

pretty tired of waiting for AA from godot, considering that FXAA is stale, TAA is broken (motion smear).

Tested the two out, HHAA is good but you were right about it being very aggressive as it does not seem to like particle effects whatsoever.

Screenshot (133)

This is using the default values for the hhaa-d shader.

Xynonners commented 7 months ago

Hey all, just dropping in to add that it is actually possible to implement / port reshade AA to gdshader. here is my LXAA port: https://gist.github.com/Xynonners/6e50a27d562829469281be45b039ec93 and here is HHAA (a weird mishmash bespoke algorithm I made for 3D): https://gist.github.com/Xynonners/ddf30a5215a59db5690f6420621f0623 someone smarter than me could probably do a CMAA2 port if they wanted to. pretty tired of waiting for AA from godot, considering that FXAA is stale, TAA is broken (motion smear).

Tested the two out, HHAA is good but you were right about it being very aggressive as it does not seem to like particle effects whatsoever.

Screenshot (133)

This is using the default values for the hhaa-d shader.

yeah, after making HHAA-D, I did a whole bunch more testing and ironed out the bugs. The edge detection in HHAA originally had a ton of false positives that were being dropped later on by the blending technique.

I made an improved version called AHAA (actually being used in a shipgame now), maybe that would be better? https://gist.github.com/Xynonners/0edfc4ce5cab61f545041752e53b3f5b

also, another thing is that it is VERY important to set the render_priority of the ShaderMaterial to -128 (also causes the noise issue).

Beanibirb commented 7 months ago

Hey all, just dropping in to add that it is actually possible to implement / port reshade AA to gdshader. here is my LXAA port: https://gist.github.com/Xynonners/6e50a27d562829469281be45b039ec93 and here is HHAA (a weird mishmash bespoke algorithm I made for 3D): https://gist.github.com/Xynonners/ddf30a5215a59db5690f6420621f0623 someone smarter than me could probably do a CMAA2 port if they wanted to. pretty tired of waiting for AA from godot, considering that FXAA is stale, TAA is broken (motion smear).

Tested the two out, HHAA is good but you were right about it being very aggressive as it does not seem to like particle effects whatsoever. Screenshot (133) This is using the default values for the hhaa-d shader.

yeah, after making HHAA-D, I did a whole bunch more testing and ironed out the bugs. The edge detection in HHAA originally had a ton of false positives that were being dropped later on by the blending technique.

I made an improved version called AHAA (actually being used in a shipgame now), maybe that would be better? https://gist.github.com/Xynonners/0edfc4ce5cab61f545041752e53b3f5b

also, another thing is that it is VERY important to set the render_priority of the ShaderMaterial to -128 (also causes the noise issue).

The render_priority was the only thing that was messing me up, thank you so very much for this

Jamsers commented 3 months ago

The recent fantastic progress on implementing motion blur as a Compositor effect has got me thinking - how hard would it be to implement SMAA as a compositor effect? ᵃⁿᵈ ʷᵒᵘˡᵈ ᵃⁿʸᵒⁿᵉ ᵇᵉ ʷⁱˡˡⁱⁿᵍ ᵗᵒ ⁱᵐᵖˡᵉᵐᵉⁿᵗ ⁱᵗ ᵖˡᵉᵃˢᵉ 😁

Calinou commented 3 months ago

how hard would it be to implement SMAA as a compositor effect?

I think it's within the realm of possibility, as multipass effects can be implemented this way. In fact, it's probably easier than motion blur since SMAA only depends on the color buffer (at least in its higher quality modes, which are most relevant in 2024).

RGDTAB commented 2 months ago

Just made an SMAA compositor effect here. It's only SMAA 1x, but I plan on working on T2x soon.

Jamsers commented 2 months ago

Raymond there's nothing else to say, you're based, you're a chad, you are him, and all the other Gen Z superlatives I can muster 💖💖💖

I've tested the compositor effect and it's perfect. Looks exactly as you'd expect, works at differing render scales, costs pretty much nothing in terms of performance.

For anyone else looking to use RGDTAB's compositor effect, I heavilly recommend setting the edge detection method to color and the quality to at least high. (medium and below disables diagonal and corner detection, which has a disproportionate cost to quality compared to the meager performance benefits)

mrjustaguy commented 2 months ago

Color isn't the best, it'll introduce Moire artifacts (similar to FXAA) on some objects with High frequency textures:

SMAA Color Ultra (same happens on all other settings) image

SMAA Luma Ultra (same on all other settings) image

As the person who made a PR (https://github.com/godotengine/godot/pull/89582) to update Godot's FXAA to Nvidia's FXAA version 3.11 I'm glad you've made that essentially obsolete for Godot IMHO, and I'm looking forward to seeing what other modes of SMAA will be like in Godot

Probably Best Settings to use are the Luma mode on High

Jamsers commented 2 months ago

Moire on patterns is an expected (and acceptable) side effect of full morphological AA - the alternative would be not touching certain parts of the image, which would allow aliasing.

IIRC both Jorge Jimenez (the creator of SMAA) and Christian Jensen (implemented SMAA for SweetFX) have confirmed that Luma was always meant to be a less accurate but faster mode, and is pretty much just a legacy leftover from the old days. Using Luma in actual game scenarios, you'll miss out on anti-aliasing texture detail, foliage, and even edges within shadowed areas.

In SweetFX, which would pretty much be the reference implementation nowadays since games stopped using SMAA, the default is Color and Ultra - but with threshold set to 0.1 rather than 0.05.

mrjustaguy commented 2 months ago

well seems something is wrong with SMAA implementation if so, as there's virtually no difference in any of the scenarios mentioned, in fact upon further testing it isn't really providing AA for Shadows at all (past the dithering a little)

Jamsers commented 2 months ago

Not the shadows: objects and surfaces in shadow. Basically scenarios where there's low luminance contrast and only high color contrast. This was more relevant back in the old days where lots of open world games only had IBL as ambient light as opposed to the fancier bounce lighting we tend to have nowadays, but is fundamentally relevant to the difference of the two approaches.

Luma:

luma_medium

Color:

color_medium

Open the images in fullscreen, note the boundary between tree bark and tree leaves, and the grass.

mrjustaguy commented 2 months ago

as far as SMAAT2x is concerned, jittering the camera could be a problem, as Camera3D doesn't allow you to modify the Projection, although it Does allow you to get it using get_camera_projection which even has a jitter_offset that you could use on the projection, there's just seemingly no way to feed it back to the camera, and the other option of just changing raw position of the camera could pose issues if the player is modifying the camera position themselves..

RGDTAB commented 2 months ago

Yeah, you're right. It looks like there's an open PR to allow custom Camera3D projection matrices, so once that gets merged I'll start work on it. In the meantime I'll try and tackle SMAAS2x. It should be possible in theory, but we'll see.

Beanibirb commented 2 months ago

Just made an SMAA compositor effect here. It's only SMAA 1x, but I plan on working on T2x soon.

This is actually amazing dude THANK YOU