- 
          
 - 
                Notifications
    
You must be signed in to change notification settings  - Fork 23.5k
 
Add contact hardening and fresnel based roughness to reflection probes reflections when using box projection #106292
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
base: master
Are you sure you want to change the base?
Conversation
38c7aca    to
    2d34dc6      
    Compare
  
    | 
           This looks pretty good, but I am a little worried about how complex it is. What was the reason for going with something custom instead of using the approach from Frostbite described in https://seblagarde.wordpress.com/wp-content/uploads/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf (page 72)?  | 
    
          
 I just built it upon Calinous initial implementation. I found the issues with it were just due to fresnel not being taken into account for roughness, I suspect that frostbite implementation by itself would have the same issue since just that formula by itself would also select a mipmap regardless of viewing angle. *Note that the roughness on the floor doesn't match, focus on the ceiling in these comparisons. :) 25_05_10_16_16__godot.windows.editor.x86_64_52AeOAWQJ3.mp4Custom implementation: 25_05_12_10_59__godot.windows.editor.x86_64_0Yg9maUqeR.mp4Cycles (Ignore the floor here, as I forgot to adjust the roughness to match): 25_05_10_16_19__blender_5uHMwvve61.mp4 | 
    
| 
           Is it planned to port this code to Mobile and Compatibility too (like my original PR)?  | 
    
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
          
 Mobile works already as it runs the same   | 
    
2d34dc6    to
    7d1a4b2      
    Compare
  
    | 
               | 
          ||
| float distance_to_hit_point = 0.0; | ||
| float mip = sqrt(roughness) * MAX_ROUGHNESS_LOD; | ||
| float mip_min = pow(roughness, 2.0) * MAX_ROUGHNESS_LOD; // Ensures fully rough materials don't have reflection contact hardening. | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Squaring roughness doesn't make sense here. Previously we sqrted the roughness value because that is how we mapped roughness to the array layers when baking the reflection probe. Therefore mip_min doesn't really make any sense, it is an arbitrary value that is small than mip but converges with mip at 0 and 1.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is an arbitrary value that is small than mip but converges with mip at 0 and 1
This is done to prevent fully rough surfaces exhibiting reflections. If we just lerp from 0.0 to mip, there will always be mirror-like reflections where distance_to_hit_point is small, regardless the roughness. This fades out the hardening effect as the roughness is increased, which produces results significantly closer to Cycles and SSR.
In the frostbite implementation this is handled by doing return lerp ( newLinearRoughness , linearRoughness , linearRoughness ), they state the same reasoning:
This works decently for low roughness values but becomes inaccurate for high roughness. In order to avoid this issue and since this effect is more visible for low roughness values, we linearly interpolate the “distance based roughness” to the original roughness, based on roughness values.
| fresnel = pow(fresnel, 2.0); | ||
| 
               | 
          ||
| float reflection_roughness = distance_to_hit_point * (1.0 - fresnel); // Adjust contact hardening strength by viewing angle. | ||
| reflection_roughness /= MAX_ROUGHNESS_LOD; | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like an arbitrary amount. MAX_ROUGHNESS_LOD is set by rendering/reflections/sky_reflections/roughness_layers which has no relationship to the fresnel value or the distance to hit point. It doesn't really make sense here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It remaps the distance_to_hit_point range based on the amount of mips. This makes it so that the perceived roughness on the surfaces remains more or less the same between different MAX_ROUGHNESS_LOD values (to the extent that that is possible).
Comparisons between various roughness_layers settings (Note the FPS difference to the commented out version):

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've adjusted this so reflection_roughness is established by doing that remap by dividing by MAX_ROUGHNESS_LOD, instead of doing that fresnel multiplication first. Makes a little more intuitive sense this way.
        
          
                servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
              
                Outdated
          
            Show resolved
            Hide resolved
        
      2637f38    to
    e9a71e6      
    Compare
  
    9807460    to
    3ee5c2d      
    Compare
  
    | ref_normal = (local_matrix * vec4(ref_normal, 0.0)).xyz; | ||
| 
               | 
          ||
| float mip = sqrt(roughness) * MAX_ROUGHNESS_LOD; | ||
| float mip_min = pow(roughness, 2.0) * MAX_ROUGHNESS_LOD; // Ensures fully rough materials don't have reflection contact hardening. | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| float mip_min = pow(roughness, 2.0) * MAX_ROUGHNESS_LOD; // Ensures fully rough materials don't have reflection contact hardening. | |
| float mip_min = (roughness * roughness) * MAX_ROUGHNESS_LOD; // Ensures fully rough materials don't have reflection contact hardening. | 
I would feel better if you avoided the pow function in this case. Sure, some compilers might recognize that this has an integer exponent of two, but I would rather not rely on that.
| vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz; | ||
| 
               | 
          ||
| float mip = sqrt(roughness) * MAX_ROUGHNESS_LOD; | ||
| float mip_min = pow(roughness, 2.0) * MAX_ROUGHNESS_LOD; // Ensures fully rough materials don't have reflection contact hardening. | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, I don't trust mobile compilers to realize that the pow can be computed with a single multiplication.
| 
           I've done a bit more thinking on this implementation vs. Frostbites,  The main thing I believe this calculation aims to achieve is make the mip selection relative to the size of the probe: Reflection probes resolutions are static, so the cubemap of a probe of 5x5 meters has the same resolution as a probe of 50x50 meters, so the texel sizes (and in turn the perceived roughness) can vary wildly, the mip selection should take this into account. Edit:  | 
    
| ref_normal = posonbox - box_offset.xyz; | ||
| 
               | 
          ||
| float fresnel = 1.0 - max(dot(normal, -normalize(vertex)), 0.0); | ||
| fresnel = pow(fresnel, 2.0); | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here as well
…s reflections when using box projection Co-authored-by: Calinou <[email protected]>
3ee5c2d    to
    54e5112      
    Compare
  
    





Closes godotengine/godot-proposals#11670
Supersedes #104585
Adds contact hardening and fresnel based roughness to reflection probes reflections when box projection is enabled.
Screenshots on master and PR are with #106241