Allow black metallic materials to reflect IBL #69522
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes the other half of #69476
@fracteed and I have been discussing this change at length today. This PR restores a behaviour that was present in Godot 3.x and was only removed this year in #63587 (in response to #40753 and godotengine/godot-proposals#4818).
Background
In Godot 3.x there was no way to disable specular reflections. Many users requested the ability, often pointing out that in other engines specular reflections can be disabled in dieletric materials by setting
specular
to0.0
(in Godot this only adjusted the specular lobe of lights). In response, I implemented #63587 which relies on a hack that Filament calls "Pre-baked Specular Occlusion". The idea is basically that no materially can have a specular value of less than 0.02, so we can treat a specular value of less than 0.02 as a signal to shut off specular reflections entirely. In other words, we can treat a specular of less than 0.02 as a form of baked occlusion. This hack is used in Filament, Unreal Engine, and Frostbite to my knowledge.Trouble arises when we consider metallic materials. For metals, their specular value comes directly from their albedo, the
specular
property isn't used. Therefore, metals with an albedo of (0,0,0) were subject to this change as well. In effect any metal with an albedo of (0,0,0) became a perfectly black absorbing material.This created two inconsistencies:
specular
is also0.0
Further, as pointed out in #69476 it can be desirable to have a metal material with an albedo of (0,0,0) still have some fresnel reflectance, but this was made impossible by #63587
Finally, the reason I have had difficulty with this is that we have two knowledgeable users at odds over what the behaviour should be.
In godotengine/godot-proposals#4818 @mindinsomnia specifically pointed out that albedo metals should have no reflection in order to match the behaviour in Unreal Engine, unity, and Eevee (note, it only actually matches the behaviour in Unreal Engine).
In #69476 @fracteed has requested that the behaviour be changed back (only for black albedo metals) in order to be consistent with Eevee, Substance, and Unity.
Part of what makes this tricky is that Eevee used to disable reflections for black albedo metals. But in newer versions has changed to the behaviour in this PR where specular reflections are partially enabled.
Underpinning all this discussion is the fact that metals with an albedo of less than 0.66 don't exist in nature, so there is no solid PBR theory underpinning the difference between the two behaviours (which is why I consistently refer to this and #63587 as hacks)
Implementation
The specular occlusion trick works by expanding the 0.02 range of the
specular
parameter to 0-1 (essentially a multiplication by 50) then clamping to the 0-1 range. We exploit that by replacing the 0 with metallic, so the range becomes metallic-1. For metallic materials, this nullifies specular occlusion entirely, but allows it to gradually fade in if metallic is used to blend between a metal and dialectric. In theory this should not create any extra shader instructions and so should be essentially free.Reasoning
The reason I think this change is worth making is twofold:
The following examples use:
metallic = 1.0
specular = 0.5
albedo = (0,0,0)
roughness = 0.0
Before:
After
Note that the center is dark, but the reflection increases strength as it approaches the edge.