Fallback to (specular) transmitted environment light when there's no transmitted background

This commit is contained in:
Marco Buono 2023-04-16 17:11:42 -03:00
parent 294a677b20
commit 5bfe6bb342
2 changed files with 24 additions and 17 deletions

View File

@ -330,27 +330,34 @@ fn pbr(
let environment_light = environment_map_light(perceptual_roughness, roughness, diffuse_color, NdotV, f_ab, in.N, R, F0);
indirect_light += (environment_light.diffuse * occlusion) + environment_light.specular;
if diffuse_transmission > 0.0 {
// NOTE: We use the diffuse transmissive color, the second Lambertian lobe's calculated
// world position, inverted normal and view vectors, and the following simplified
// values for a fully diffuse transmitted light contribution approximation:
// we'll use the specular component of the transmitted environment
// light in the call to `transmissive_light()` below
var transmitted_environment_light_specular = vec3<f32>(0.0);
if diffuse_transmission > 0.0 || transmission > 0.0 {
// NOTE: We use the diffuse transmissive color, inverted normal and view vectors,
// and the following simplified values for the transmitted environment light contribution
// approximation:
//
// perceptual_roughness = 1.0;
// roughness = 1.0;
// NdotV = 1.0;
// f_ab = vec2<f32>(0.1)
// R = vec3<f32>(0.0) // doesn't really matter
// F0 = vec3<f32>(0.0)
// R = -refract(in.V, -in.N, 1.0 / ior)
// F0 = vec3<f32>(0.16)
// occlusion = 1.0
let environment_light = environment_map_light(1.0, 1.0, diffuse_transmissive_color, 1.0, vec2<f32>(0.1), -in.N, vec3<f32>(0.0), vec3<f32>(0.0));
transmitted_light += environment_light.diffuse;
let transmitted_environment_light = environment_map_light(perceptual_roughness, roughness, diffuse_transmissive_color, 1.0, vec2<f32>(0.1), -in.N, -refract(in.V, -in.N, 1.0 / ior), vec3<f32>(0.16));
transmitted_light += transmitted_environment_light.diffuse;
transmitted_environment_light_specular = transmitted_environment_light.specular;
}
#else
// If there's no environment map light, there's no transmitted environment
// light specular component, so we can just hardcode it to zero.
let transmitted_environment_light_specular = vec3<f32>(0.0);
#endif
let emissive_light = emissive.rgb * output_color.a;
if transmission > 0.0 {
transmitted_light += transmissive_light(in.world_position, in.frag_coord.xyz, in.N, in.V, ior, thickness, perceptual_roughness, transmissive_color).rgb;
transmitted_light += transmissive_light(in.world_position, in.frag_coord.xyz, in.N, in.V, ior, thickness, perceptual_roughness, transmissive_color, transmitted_environment_light_specular).rgb;
}
// Total light

View File

@ -281,7 +281,7 @@ fn directional_light(light_id: u32, roughness: f32, NdotV: f32, normal: vec3<f32
return (specular_light + diffuse) * (*light).color.rgb * NoL;
}
fn transmissive_light(world_position: vec4<f32>, frag_coord: vec3<f32>, N: vec3<f32>, V: vec3<f32>, ior: f32, thickness: f32, perceptual_roughness: f32, transmissive_color: vec3<f32>) -> vec3<f32> {
fn transmissive_light(world_position: vec4<f32>, frag_coord: vec3<f32>, N: vec3<f32>, V: vec3<f32>, ior: f32, thickness: f32, perceptual_roughness: f32, transmissive_color: vec3<f32>, transmitted_environment_light_specular: vec3<f32>) -> vec3<f32> {
// Calculate distance, used to scale roughness transmission blur
let distance = length(view.world_position - world_position.xyz);
@ -308,12 +308,12 @@ fn transmissive_light(world_position: vec4<f32>, frag_coord: vec3<f32>, N: vec3<
// Fetch background color
let background_color = fetch_transmissive_background(offset_position, frag_coord, perceptual_roughness, distance);
// Calculate final color by applying transmissive color to background
// Calculate final color by applying transmissive color to a mix of background color and transmitted specular environment light
// TODO: Add support for attenuationColor and attenuationDistance
return transmissive_color * background_color;
return transmissive_color * mix(transmitted_environment_light_specular, background_color.rgb, background_color.a);
}
fn fetch_transmissive_background(offset_position: vec2<f32>, frag_coord: vec3<f32>, perceptual_roughness: f32, distance: f32) -> vec3<f32> {
fn fetch_transmissive_background(offset_position: vec2<f32>, frag_coord: vec3<f32>, perceptual_roughness: f32, distance: f32) -> vec4<f32> {
// Calculate view aspect ratio, used to scale offset so that it's proportionate
let aspect = view.viewport.z / view.viewport.w;
@ -331,7 +331,7 @@ fn fetch_transmissive_background(offset_position: vec2<f32>, frag_coord: vec3<f3
// Number of taps scale with blur intensity
// Minimum: 1, Maximum: 9
let num_taps = i32(max(blur_intensity * 300.0, 8.0)) + 1;
var result = vec3<f32>(0.0, 0.0, 0.0);
var result = vec4<f32>(0.0);
for (var i: i32 = 0; i < num_taps; i = i + 1) {
// Magic numbers have been empirically chosen to produce blurry results that look smooth
let dither = screen_space_dither(frag_coord.xy + vec2<f32>(f32(i) * 4773.0, f32(i) * 1472.0));
@ -343,7 +343,7 @@ fn fetch_transmissive_background(offset_position: vec2<f32>, frag_coord: vec3<f3
view_transmission_texture,
view_transmission_sampler,
offset_position + dither_offset,
).rgb;
);
}
result /= f32(num_taps);