Skip to content

Add specular occlusion from ambient light#106145

Merged
Repiteo merged 1 commit intogodotengine:masterfrom
lander-vr:ambient-light-specular-occlusion
May 9, 2025
Merged

Add specular occlusion from ambient light#106145
Repiteo merged 1 commit intogodotengine:masterfrom
lander-vr:ambient-light-specular-occlusion

Conversation

@lander-vr
Copy link
Contributor

Closes godotengine/godot-proposals#8637
Supersedes #86102

This is a rebase and rework of @guerro323's specular occlusion PR.

There's a few fundamental changes:

  • Specular occlusion is now based on ambient light instead of just the lightmap. This has the benefit of providing specular occlusion for any object regardless of whether they are lightmapped or not.
  • Because of this, AO also provides specular occlusion now. (This is relevant for Add support for bent normal maps for specular occlusion and indirect lighting #89988, as it also implements specular occlusion from AO)
  • In accordance with it not being based off of just lightmaps now, the setting has been moved to reflections.
  • Instead of various modes, it is now a toggle. Either it is enabled or disabled. This is because the "Reduce" method worked very poorly on shiny surfaces, strayed further from ground truth, and simply looked worse.
  • The implementation is a little simpler.
  • This PR does a slightly better job at maintaining reflections that shouldn't be occluded, occluding reflections only once the ambient lighting crosses a certain threshold.

I'm not sure whether or not the project setting should still force a restart, since the implementation is cheaper and simpler now.

Forward+

Disabled Enabled
image image
image image
image image
image image

Mobile

Disabled Enabled
image image

Compatibility

Disabled Enabled
image image

Tile-room test-scene is a quick remake of the scene in this Unity forum post

@lander-vr lander-vr requested review from a team as code owners May 7, 2025 12:51
@lander-vr lander-vr force-pushed the ambient-light-specular-occlusion branch from 38294e8 to 7df3ce1 Compare May 7, 2025 13:01
@Chaosus Chaosus added this to the 4.x milestone May 7, 2025
@passivestar
Copy link
Contributor

passivestar commented May 8, 2025

Nice!

Master PR
before after
before2 after2

Edit: In my initial test above I was using tonemapper exposure to make the resulting image brighter. However per @lander-vr's suggestion I tried to use camera exposure instead. This brought out reflections on open surfaces more, while corners still remain occluded, which gives a better result:

after4

@lander-vr lander-vr force-pushed the ambient-light-specular-occlusion branch from 7df3ce1 to 54e638a Compare May 8, 2025 14:52
@clayjohn clayjohn modified the milestones: 4.x, 4.5 May 8, 2025
@lander-vr lander-vr force-pushed the ambient-light-specular-occlusion branch 2 times, most recently from e405e3a to a17b656 Compare May 8, 2025 17:09
Copy link
Member

@Calinou Calinou left a comment

Choose a reason for hiding this comment

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

Tested locally, it works as expected. Code looks good to me.

Co-authored-by: guerro323 <kaltobattle@gmail.com>
@lander-vr lander-vr force-pushed the ambient-light-specular-occlusion branch from a17b656 to 56730d0 Compare May 8, 2025 21:52
@LiveTrower
Copy link
Contributor

This might sound silly, but I've noticed a strange behavior while testing this PR. When you have a metallic material and you gradually reduce its roughness value, it undergoes a transition where the material abruptly changes from a dark color to a lighter one. This doesn't happen when you disable specular occlusion.

2025-05-08-18-56-06.mp4

Is this expected behavior?

@lander-vr
Copy link
Contributor Author

lander-vr commented May 9, 2025

@LiveTrower Mmmh, I cannot seem to reproduce this/notice any strange behavior.

25_05_09_11_22__godot.windows.editor.x86_64_AoTQQryMkJ.mp4

What's happening in your video seems to be expected, I don't think this behavior is unusual. The effect is darkening specular lighting where ambient lighting is darker (In this case on faces with normals facing downwards),
float reflective_f = (1.0 - roughness) * metallic; ensures that metallic materials preserve more of their reflection strength, so the effect of specular occlusion is reduced as you decrease the roughness.

I don't think what's shown in your video looks out of the ordinary. Specular occlusion adds a little more depth to reflective surfaces, so it's normal for it to not be an exact match to when it is disabled.

@clayjohn What do you think?

@lander-vr
Copy link
Contributor Author

lander-vr commented May 9, 2025

After testing a little more, while I still cannot reproduce the exact effect of whats happening in your video, it looks like a culprit may be that fully rough surfaces still receive specular lighting. This seems to be the case both for metallic and non-metallic materials.
As far as I'm aware, a fully rough PBR material, regardless of metalness, should have no specular lighting. It seems like this is not the case for Godots shader. I'm not sure if that is expected due to assumptions being made in the BRDF, or if this is unintentional.

There should be no difference between these two as they're both fully rough:

Metal 0.0 - Specular 0.0 - Rough 1.0 Metal 0.0 - Specular 1.0 - Rough 1.0
image image

It's not a perfect comparison, but if we compare a fully rough principled shader to a diffuse shader in Blender, we see an exact match:

Blender Diffuse BSDF Blender Principled BSDF
image image

This is also the reason why when LiveTrower toggles the disable specular occlusion flag in their video we see a change in shading on their 100% rough material.

Either way, this is not something caused by how specular occlusion is tackled by this PR though. After having tested again with a bunch of different ambient light strengths I think it's safe to say that the feature does behave as expected.

@LiveTrower
Copy link
Contributor

@lander-vr As far as I know, default Godot shaders use diffuse Lambert by default, and StandardMaterials use diffuse Burley by default, so that could explain a different behavior.

@ettiSurreal
Copy link
Contributor

ettiSurreal commented May 9, 2025

It's not a perfect comparison, but if we compare a fully rough principled shader to a diffuse shader in Blender, we see an exact match:

It's not an exact match. I will provide a very exaggerated example.
Both materials are on default settings other than roughness being 1.0 on Principled BSDF and color being solid black.
Color Management exposure is also set to 5.0.

Diffuse BSDF Principled BSDF
image image

@Repiteo Repiteo merged commit 821170f into godotengine:master May 9, 2025
20 checks passed
@Repiteo
Copy link
Contributor

Repiteo commented May 9, 2025

Thanks!

@lander-vr lander-vr deleted the ambient-light-specular-occlusion branch May 9, 2025 17:00
@Calinou
Copy link
Member

Calinou commented May 10, 2025

There should be no difference between these two as they're both fully rough:

See this PR for context as to why some specularity is left by default: #63587

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.

Add a cheap specular occlusion for LightmapGI

8 participants