diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 2814f41c3767..43e5c7f94481 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1666,6 +1666,8 @@ void reflection_process(samplerCube reflection_map, vec3 ref_normal = normalize(reflect(vertex, normal)); 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. if (use_box_project) { //box project vec3 nrdir = normalize(ref_normal); @@ -1673,13 +1675,23 @@ void reflection_process(samplerCube reflection_map, vec3 rbmin = (-box_extents - local_pos) / nrdir; vec3 rbminmax = mix(rbmin, rbmax, vec3(greaterThan(nrdir, vec3(0.0, 0.0, 0.0)))); + float distance_to_hit_point = min(min(rbminmax.x, rbminmax.y), rbminmax.z); - float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); - vec3 posonbox = local_pos + nrdir * fa; + vec3 posonbox = local_pos + nrdir * distance_to_hit_point; ref_normal = posonbox - box_offset.xyz; + + float fresnel = 1.0 - max(dot(normal, -normalize(vertex)), 0.0); + fresnel = pow(fresnel, 2.0); + + float reflection_roughness = distance_to_hit_point / MAX_ROUGHNESS_LOD; // Remap distance to be relative to amount of mips. + reflection_roughness *= 1.0 - fresnel; + reflection_roughness += ((1.0 - fresnel) * sqrt(roughness)); // Increase roughness when viewing angle is perpendicular to avoid overly sharp reflections on rough surfaces. + + float mip_offset = clamp(reflection_roughness, 0.0, 1.0); // Compute new mip level based on the mip offset value (this is mostly arbitrary). + mip = mix(mip_min, mip, mip_offset); } - reflection.rgb = srgb_to_linear(textureLod(reflection_map, ref_normal, roughness * MAX_ROUGHNESS_LOD).rgb); + reflection.rgb = srgb_to_linear(textureLod(reflection_map, ref_normal, mip).rgb); if (exterior) { reflection.rgb = mix(skybox, reflection.rgb, blend); diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl index a17cf43d1a95..0e16e8fbb3b7 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -930,6 +930,8 @@ void reflection_process(uint ref_index, vec3 vertex, hvec3 ref_vec, hvec3 normal 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. if (reflections.data[ref_index].box_project) { //box project vec3 nrdir = normalize(local_ref_vec); @@ -937,16 +939,26 @@ void reflection_process(uint ref_index, vec3 vertex, hvec3 ref_vec, hvec3 normal vec3 rbmin = (-box_extents - local_pos) / nrdir; vec3 rbminmax = mix(rbmin, rbmax, greaterThan(nrdir, vec3(0.0, 0.0, 0.0))); + float distance_to_hit_point = min(min(rbminmax.x, rbminmax.y), rbminmax.z); - float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); - vec3 posonbox = local_pos + nrdir * fa; + vec3 posonbox = local_pos + nrdir * distance_to_hit_point; local_ref_vec = posonbox - reflections.data[ref_index].box_offset; + + float fresnel = 1.0 - max(dot(normal, -normalize(vertex)), 0.0); + fresnel = pow(fresnel, 4.0); + + float reflection_roughness = distance_to_hit_point / MAX_ROUGHNESS_LOD; // Remap distance to be relative to amount of mips. + reflection_roughness *= 1.0 - fresnel; + reflection_roughness += ((1.0 - fresnel) * sqrt(roughness)); // Increase roughness when viewing angle is perpendicular to avoid overly sharp reflections on rough surfaces. + + float mip_offset = clamp(reflection_roughness, 0.0, 1.0); // Compute new mip level based on the mip offset value (this is mostly arbitrary). + mip = mix(mip_min, mip, mip_offset); } hvec4 reflection; half reflection_blend = max(half(0.0), blend - reflection_accum.a); - 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(); + 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(); reflection.rgb *= half(reflections.data[ref_index].exposure_normalization); reflection.a = reflection_blend;