Skip to content

Commit 54e5112

Browse files
lander-vrCalinou
andcommitted
Add contact hardening and fresnel based roughness to reflection probes reflections when using box projection
Co-authored-by: Calinou <[email protected]>
1 parent 8aa37ca commit 54e5112

File tree

2 files changed

+30
-6
lines changed

2 files changed

+30
-6
lines changed

drivers/gles3/shaders/scene.glsl

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,20 +1666,32 @@ void reflection_process(samplerCube reflection_map,
16661666
vec3 ref_normal = normalize(reflect(vertex, normal));
16671667
ref_normal = (local_matrix * vec4(ref_normal, 0.0)).xyz;
16681668

1669+
float mip = sqrt(roughness) * MAX_ROUGHNESS_LOD;
1670+
float mip_min = pow(roughness, 2.0) * MAX_ROUGHNESS_LOD; // Ensures fully rough materials don't have reflection contact hardening.
16691671
if (use_box_project) { //box project
16701672

16711673
vec3 nrdir = normalize(ref_normal);
16721674
vec3 rbmax = (box_extents - local_pos) / nrdir;
16731675
vec3 rbmin = (-box_extents - local_pos) / nrdir;
16741676

16751677
vec3 rbminmax = mix(rbmin, rbmax, vec3(greaterThan(nrdir, vec3(0.0, 0.0, 0.0))));
1678+
float distance_to_hit_point = min(min(rbminmax.x, rbminmax.y), rbminmax.z);
16761679

1677-
float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z);
1678-
vec3 posonbox = local_pos + nrdir * fa;
1680+
vec3 posonbox = local_pos + nrdir * distance_to_hit_point;
16791681
ref_normal = posonbox - box_offset.xyz;
1682+
1683+
float fresnel = 1.0 - max(dot(normal, -normalize(vertex)), 0.0);
1684+
fresnel = pow(fresnel, 2.0);
1685+
1686+
float reflection_roughness = distance_to_hit_point / MAX_ROUGHNESS_LOD; // Remap distance to be relative to amount of mips.
1687+
reflection_roughness *= 1.0 - fresnel;
1688+
reflection_roughness += ((1.0 - fresnel) * sqrt(roughness)); // Increase roughness when viewing angle is perpendicular to avoid overly sharp reflections on rough surfaces.
1689+
1690+
float mip_offset = clamp(reflection_roughness, 0.0, 1.0); // Compute new mip level based on the mip offset value (this is mostly arbitrary).
1691+
mip = mix(mip_min, mip, mip_offset);
16801692
}
16811693

1682-
reflection.rgb = srgb_to_linear(textureLod(reflection_map, ref_normal, roughness * MAX_ROUGHNESS_LOD).rgb);
1694+
reflection.rgb = srgb_to_linear(textureLod(reflection_map, ref_normal, mip).rgb);
16831695

16841696
if (exterior) {
16851697
reflection.rgb = mix(skybox, reflection.rgb, blend);

servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -930,23 +930,35 @@ void reflection_process(uint ref_index, vec3 vertex, hvec3 ref_vec, hvec3 normal
930930

931931
vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz;
932932

933+
float mip = sqrt(roughness) * MAX_ROUGHNESS_LOD;
934+
float mip_min = pow(roughness, 2.0) * MAX_ROUGHNESS_LOD; // Ensures fully rough materials don't have reflection contact hardening.
933935
if (reflections.data[ref_index].box_project) { //box project
934936

935937
vec3 nrdir = normalize(local_ref_vec);
936938
vec3 rbmax = (box_extents - local_pos) / nrdir;
937939
vec3 rbmin = (-box_extents - local_pos) / nrdir;
938940

939941
vec3 rbminmax = mix(rbmin, rbmax, greaterThan(nrdir, vec3(0.0, 0.0, 0.0)));
942+
float distance_to_hit_point = min(min(rbminmax.x, rbminmax.y), rbminmax.z);
940943

941-
float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z);
942-
vec3 posonbox = local_pos + nrdir * fa;
944+
vec3 posonbox = local_pos + nrdir * distance_to_hit_point;
943945
local_ref_vec = posonbox - reflections.data[ref_index].box_offset;
946+
947+
float fresnel = 1.0 - max(dot(normal, -normalize(vertex)), 0.0);
948+
fresnel = pow(fresnel, 4.0);
949+
950+
float reflection_roughness = distance_to_hit_point / MAX_ROUGHNESS_LOD; // Remap distance to be relative to amount of mips.
951+
reflection_roughness *= 1.0 - fresnel;
952+
reflection_roughness += ((1.0 - fresnel) * sqrt(roughness)); // Increase roughness when viewing angle is perpendicular to avoid overly sharp reflections on rough surfaces.
953+
954+
float mip_offset = clamp(reflection_roughness, 0.0, 1.0); // Compute new mip level based on the mip offset value (this is mostly arbitrary).
955+
mip = mix(mip_min, mip, mip_offset);
944956
}
945957

946958
hvec4 reflection;
947959
half reflection_blend = max(half(0.0), blend - reflection_accum.a);
948960

949-
reflection.rgb = hvec3(textureLod(samplerCubeArray(reflection_atlas, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(local_ref_vec, reflections.data[ref_index].index), sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb) * sc_luminance_multiplier();
961+
reflection.rgb = hvec3(textureLod(samplerCubeArray(reflection_atlas, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(local_ref_vec, reflections.data[ref_index].index), mip).rgb) * sc_luminance_multiplier();
950962
reflection.rgb *= half(reflections.data[ref_index].exposure_normalization);
951963
reflection.a = reflection_blend;
952964

0 commit comments

Comments
 (0)