Use frostbite's specular sampling direction for environment map light (#16711)
Adopt a slightly more accurate lighting model. Before:  After:  ## Changelog - EnvironmentMapLight lighting is now slightly more realistic for metallic materials with high roughness
This commit is contained in:
parent
1e5d2c8867
commit
1666b1c497
@ -4,9 +4,7 @@
|
||||
#import bevy_pbr::mesh_view_bindings as bindings
|
||||
#import bevy_pbr::mesh_view_bindings::light_probes
|
||||
#import bevy_pbr::mesh_view_bindings::environment_map_uniform
|
||||
#import bevy_pbr::lighting::{
|
||||
F_Schlick_vec, LayerLightingInput, LightingInput, LAYER_BASE, LAYER_CLEARCOAT
|
||||
}
|
||||
#import bevy_pbr::lighting::{F_Schlick_vec, LightingInput, LayerLightingInput, LAYER_BASE, LAYER_CLEARCOAT}
|
||||
#import bevy_pbr::clustered_forward::ClusterableObjectIndexRanges
|
||||
|
||||
struct EnvironmentMapLight {
|
||||
@ -26,16 +24,17 @@ struct EnvironmentMapRadiances {
|
||||
#ifdef MULTIPLE_LIGHT_PROBES_IN_ARRAY
|
||||
|
||||
fn compute_radiances(
|
||||
input: ptr<function, LightingInput>,
|
||||
input: LayerLightingInput,
|
||||
clusterable_object_index_ranges: ptr<function, ClusterableObjectIndexRanges>,
|
||||
layer: u32,
|
||||
world_position: vec3<f32>,
|
||||
found_diffuse_indirect: bool,
|
||||
) -> EnvironmentMapRadiances {
|
||||
// Unpack.
|
||||
let perceptual_roughness = (*input).layers[layer].perceptual_roughness;
|
||||
let N = (*input).layers[layer].N;
|
||||
let R = (*input).layers[layer].R;
|
||||
let N = input.N;
|
||||
let R = input.R;
|
||||
let NdotV = input.NdotV;
|
||||
let perceptual_roughness = input.perceptual_roughness;
|
||||
let roughness = input.roughness;
|
||||
|
||||
var radiances: EnvironmentMapRadiances;
|
||||
|
||||
@ -65,7 +64,7 @@ fn compute_radiances(
|
||||
|
||||
if (!found_diffuse_indirect) {
|
||||
var irradiance_sample_dir = N;
|
||||
// Rotating the world space ray direction by the environment light map transform matrix, it is
|
||||
// Rotating the world space ray direction by the environment light map transform matrix, it is
|
||||
// equivalent to rotating the diffuse environment cubemap itself.
|
||||
irradiance_sample_dir = (environment_map_uniform.transform * vec4(irradiance_sample_dir, 1.0)).xyz;
|
||||
// Cube maps are left-handed so we negate the z coordinate.
|
||||
@ -77,8 +76,8 @@ fn compute_radiances(
|
||||
0.0).rgb * query_result.intensity;
|
||||
}
|
||||
|
||||
var radiance_sample_dir = R;
|
||||
// Rotating the world space ray direction by the environment light map transform matrix, it is
|
||||
var radiance_sample_dir = radiance_sample_direction(N, R, roughness);
|
||||
// Rotating the world space ray direction by the environment light map transform matrix, it is
|
||||
// equivalent to rotating the specular environment cubemap itself.
|
||||
radiance_sample_dir = (environment_map_uniform.transform * vec4(radiance_sample_dir, 1.0)).xyz;
|
||||
// Cube maps are left-handed so we negate the z coordinate.
|
||||
@ -95,16 +94,17 @@ fn compute_radiances(
|
||||
#else // MULTIPLE_LIGHT_PROBES_IN_ARRAY
|
||||
|
||||
fn compute_radiances(
|
||||
input: ptr<function, LightingInput>,
|
||||
input: LayerLightingInput,
|
||||
clusterable_object_index_ranges: ptr<function, ClusterableObjectIndexRanges>,
|
||||
layer: u32,
|
||||
world_position: vec3<f32>,
|
||||
found_diffuse_indirect: bool,
|
||||
) -> EnvironmentMapRadiances {
|
||||
// Unpack.
|
||||
let perceptual_roughness = (*input).layers[layer].perceptual_roughness;
|
||||
let N = (*input).layers[layer].N;
|
||||
let R = (*input).layers[layer].R;
|
||||
let N = input.N;
|
||||
let R = input.R;
|
||||
let NdotV = input.NdotV;
|
||||
let perceptual_roughness = input.perceptual_roughness;
|
||||
let roughness = input.roughness;
|
||||
|
||||
var radiances: EnvironmentMapRadiances;
|
||||
|
||||
@ -123,7 +123,7 @@ fn compute_radiances(
|
||||
|
||||
if (!found_diffuse_indirect) {
|
||||
var irradiance_sample_dir = N;
|
||||
// Rotating the world space ray direction by the environment light map transform matrix, it is
|
||||
// Rotating the world space ray direction by the environment light map transform matrix, it is
|
||||
// equivalent to rotating the diffuse environment cubemap itself.
|
||||
irradiance_sample_dir = (environment_map_uniform.transform * vec4(irradiance_sample_dir, 1.0)).xyz;
|
||||
// Cube maps are left-handed so we negate the z coordinate.
|
||||
@ -135,8 +135,8 @@ fn compute_radiances(
|
||||
0.0).rgb * intensity;
|
||||
}
|
||||
|
||||
var radiance_sample_dir = R;
|
||||
// Rotating the world space ray direction by the environment light map transform matrix, it is
|
||||
var radiance_sample_dir = radiance_sample_direction(N, R, roughness);
|
||||
// Rotating the world space ray direction by the environment light map transform matrix, it is
|
||||
// equivalent to rotating the specular environment cubemap itself.
|
||||
radiance_sample_dir = (environment_map_uniform.transform * vec4(radiance_sample_dir, 1.0)).xyz;
|
||||
// Cube maps are left-handed so we negate the z coordinate.
|
||||
@ -174,9 +174,8 @@ fn environment_map_light_clearcoat(
|
||||
let inv_Fc = 1.0 - Fc;
|
||||
|
||||
let clearcoat_radiances = compute_radiances(
|
||||
input,
|
||||
(*input).layers[LAYER_CLEARCOAT],
|
||||
clusterable_object_index_ranges,
|
||||
LAYER_CLEARCOAT,
|
||||
world_position,
|
||||
found_diffuse_indirect,
|
||||
);
|
||||
@ -206,9 +205,8 @@ fn environment_map_light(
|
||||
var out: EnvironmentMapLight;
|
||||
|
||||
let radiances = compute_radiances(
|
||||
input,
|
||||
(*input).layers[LAYER_BASE],
|
||||
clusterable_object_index_ranges,
|
||||
LAYER_BASE,
|
||||
world_position,
|
||||
found_diffuse_indirect,
|
||||
);
|
||||
@ -256,3 +254,11 @@ fn environment_map_light(
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// "Moving Frostbite to Physically Based Rendering 3.0", listing 22
|
||||
// https://seblagarde.wordpress.com/wp-content/uploads/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf#page=70
|
||||
fn radiance_sample_direction(N: vec3<f32>, R: vec3<f32>, roughness: f32) -> vec3<f32> {
|
||||
let smoothness = saturate(1.0 - roughness);
|
||||
let lerp_factor = smoothness * (sqrt(smoothness) + roughness);
|
||||
return mix(N, R, lerp_factor);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user