This commit is contained in:
TheBigCheese 2025-07-16 19:05:28 -04:00 committed by GitHub
commit 10f7b5c77f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 97 additions and 133 deletions

View File

@ -4,6 +4,7 @@
pbr_types::{PbrInput, pbr_input_new, STANDARD_MATERIAL_FLAGS_UNLIT_BIT}, pbr_types::{PbrInput, pbr_input_new, STANDARD_MATERIAL_FLAGS_UNLIT_BIT},
pbr_deferred_types as deferred_types, pbr_deferred_types as deferred_types,
pbr_functions, pbr_functions,
lighting,
rgb9e5, rgb9e5,
mesh_view_bindings::view, mesh_view_bindings::view,
utils::{octahedral_encode, octahedral_decode}, utils::{octahedral_encode, octahedral_decode},
@ -64,7 +65,7 @@ fn deferred_gbuffer_from_pbr_input(in: PbrInput) -> vec4<u32> {
let metallic = in.material.metallic; let metallic = in.material.metallic;
let specular_transmission = in.material.specular_transmission; let specular_transmission = in.material.specular_transmission;
let diffuse_transmission = in.material.diffuse_transmission; let diffuse_transmission = in.material.diffuse_transmission;
let diffuse_color = pbr_functions::calculate_diffuse_color( let diffuse_color = lighting::calculate_diffuse_color(
base_color, base_color,
metallic, metallic,
specular_transmission, specular_transmission,

View File

@ -260,23 +260,6 @@ fn calculate_view(
return V; return V;
} }
// Diffuse strength is inversely related to metallicity, specular and diffuse transmission
fn calculate_diffuse_color(
base_color: vec3<f32>,
metallic: f32,
specular_transmission: f32,
diffuse_transmission: f32
) -> vec3<f32> {
return base_color * (1.0 - metallic) * (1.0 - specular_transmission) *
(1.0 - diffuse_transmission);
}
// Remapping [0,1] reflectance to F0
// See https://google.github.io/filament/Filament.html#materialsystem/parameterization/remapping
fn calculate_F0(base_color: vec3<f32>, metallic: f32, reflectance: vec3<f32>) -> vec3<f32> {
return 0.16 * reflectance * reflectance * (1.0 - metallic) + base_color * metallic;
}
#ifndef PREPASS_FRAGMENT #ifndef PREPASS_FRAGMENT
fn apply_pbr_lighting( fn apply_pbr_lighting(
in: pbr_types::PbrInput, in: pbr_types::PbrInput,
@ -288,10 +271,8 @@ fn apply_pbr_lighting(
// calculate non-linear roughness from linear perceptualRoughness // calculate non-linear roughness from linear perceptualRoughness
let metallic = in.material.metallic; let metallic = in.material.metallic;
let perceptual_roughness = in.material.perceptual_roughness; let perceptual_roughness = in.material.perceptual_roughness;
let roughness = lighting::perceptualRoughnessToRoughness(perceptual_roughness);
let ior = in.material.ior; let ior = in.material.ior;
let thickness = in.material.thickness; let thickness = in.material.thickness;
let reflectance = in.material.reflectance;
let diffuse_transmission = in.material.diffuse_transmission; let diffuse_transmission = in.material.diffuse_transmission;
let specular_transmission = in.material.specular_transmission; let specular_transmission = in.material.specular_transmission;
@ -300,67 +281,25 @@ fn apply_pbr_lighting(
let diffuse_occlusion = in.diffuse_occlusion; let diffuse_occlusion = in.diffuse_occlusion;
let specular_occlusion = in.specular_occlusion; let specular_occlusion = in.specular_occlusion;
// Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
let NdotV = max(dot(in.N, in.V), 0.0001);
let R = reflect(-in.V, in.N);
#ifdef STANDARD_MATERIAL_CLEARCOAT
// Do the above calculations again for the clearcoat layer. Remember that
// the clearcoat can have its own roughness and its own normal.
let clearcoat = in.material.clearcoat;
let clearcoat_perceptual_roughness = in.material.clearcoat_perceptual_roughness;
let clearcoat_roughness = lighting::perceptualRoughnessToRoughness(clearcoat_perceptual_roughness);
let clearcoat_N = in.clearcoat_N;
let clearcoat_NdotV = max(dot(clearcoat_N, in.V), 0.0001);
let clearcoat_R = reflect(-in.V, clearcoat_N);
#endif // STANDARD_MATERIAL_CLEARCOAT
let diffuse_color = calculate_diffuse_color(
output_color.rgb,
metallic,
specular_transmission,
diffuse_transmission
);
// Diffuse transmissive strength is inversely related to metallicity and specular transmission, but directly related to diffuse transmission // Diffuse transmissive strength is inversely related to metallicity and specular transmission, but directly related to diffuse transmission
let diffuse_transmissive_color = output_color.rgb * (1.0 - metallic) * (1.0 - specular_transmission) * diffuse_transmission; let diffuse_transmissive_color = output_color.rgb * (1.0 - metallic) * (1.0 - specular_transmission) * diffuse_transmission;
// Calculate the world position of the second Lambertian lobe used for diffuse transmission, by subtracting material thickness // Calculate the world position of the second Lambertian lobe used for diffuse transmission, by subtracting material thickness
let diffuse_transmissive_lobe_world_position = in.world_position - vec4<f32>(in.world_normal, 0.0) * thickness; let diffuse_transmissive_lobe_world_position = in.world_position - vec4<f32>(in.world_normal, 0.0) * thickness;
let F0 = calculate_F0(output_color.rgb, metallic, reflectance);
let F_ab = lighting::F_AB(perceptual_roughness, NdotV);
var direct_light: vec3<f32> = vec3<f32>(0.0); var direct_light: vec3<f32> = vec3<f32>(0.0);
// Transmitted Light (Specular and Diffuse) // Transmitted Light (Specular and Diffuse)
var transmitted_light: vec3<f32> = vec3<f32>(0.0); var transmitted_light: vec3<f32> = vec3<f32>(0.0);
// Pack all the values into a structure. var lighting_input = lighting::pbr_input_to_lighting_input(in);
var lighting_input: lighting::LightingInput; let diffuse_color = lighting_input.diffuse_color;
lighting_input.layers[LAYER_BASE].NdotV = NdotV; let F0 = lighting_input.F0_;
lighting_input.layers[LAYER_BASE].N = in.N;
lighting_input.layers[LAYER_BASE].R = R; let NdotV = lighting_input.layers[LAYER_BASE].NdotV;
lighting_input.layers[LAYER_BASE].perceptual_roughness = perceptual_roughness;
lighting_input.layers[LAYER_BASE].roughness = roughness;
lighting_input.P = in.world_position.xyz;
lighting_input.V = in.V;
lighting_input.diffuse_color = diffuse_color;
lighting_input.F0_ = F0;
lighting_input.F_ab = F_ab;
#ifdef STANDARD_MATERIAL_CLEARCOAT #ifdef STANDARD_MATERIAL_CLEARCOAT
lighting_input.layers[LAYER_CLEARCOAT].NdotV = clearcoat_NdotV; let clearcoat_NdotV = lighting_input.layers[LAYER_CLEARCOAT].NdotV;
lighting_input.layers[LAYER_CLEARCOAT].N = clearcoat_N; #endif // STANDARD_MATERIAL_CLEARCOAT
lighting_input.layers[LAYER_CLEARCOAT].R = clearcoat_R;
lighting_input.layers[LAYER_CLEARCOAT].perceptual_roughness = clearcoat_perceptual_roughness;
lighting_input.layers[LAYER_CLEARCOAT].roughness = clearcoat_roughness;
lighting_input.clearcoat_strength = clearcoat;
#endif // STANDARD_MATERIAL_CLEARCOAT
#ifdef STANDARD_MATERIAL_ANISOTROPY
lighting_input.anisotropy = in.anisotropy_strength;
lighting_input.Ta = in.anisotropy_T;
lighting_input.Ba = in.anisotropy_B;
#endif // STANDARD_MATERIAL_ANISOTROPY
// And do the same for transmissive if we need to. // And do the same for transmissive if we need to.
#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION #ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION

View File

@ -3,6 +3,7 @@
#import bevy_pbr::{ #import bevy_pbr::{
mesh_view_types::POINT_LIGHT_FLAGS_SPOT_LIGHT_Y_NEGATIVE, mesh_view_types::POINT_LIGHT_FLAGS_SPOT_LIGHT_Y_NEGATIVE,
mesh_view_bindings as view_bindings, mesh_view_bindings as view_bindings,
pbr_types::PbrInput,
} }
#import bevy_render::maths::PI #import bevy_render::maths::PI
@ -247,6 +248,82 @@ fn specular_multiscatter(
return Fr; return Fr;
} }
/// Constructs the `LightingInput` from a given `PbrInput`.
fn pbr_input_to_lighting_input(pbr_input: PbrInput) -> LightingInput {
let N = pbr_input.N;
let V = pbr_input.V;
let material = pbr_input.material;
var lighting_input: LightingInput;
lighting_input.layers[LAYER_BASE].N = N;
// Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
lighting_input.layers[LAYER_BASE].R = reflect(-V, N);
let NdotV = max(dot(N, V), 0.0001);
lighting_input.layers[LAYER_BASE].NdotV = NdotV;
lighting_input.layers[LAYER_BASE].perceptual_roughness = material.perceptual_roughness;
// calculate non-linear roughness from linear perceptualRoughness
lighting_input.layers[LAYER_BASE].roughness =
perceptualRoughnessToRoughness(material.perceptual_roughness);
lighting_input.P = pbr_input.world_position.xyz;
lighting_input.V = V;
lighting_input.diffuse_color = calculate_diffuse_color(
material.base_color.rgb,
material.metallic,
material.specular_transmission,
material.diffuse_transmission
);
lighting_input.F0_ = calculate_F0(material.base_color.rgb, material.metallic, material.reflectance);
lighting_input.F_ab = F_AB(material.perceptual_roughness, NdotV);
#ifdef STANDARD_MATERIAL_CLEARCOAT
// Do the above calculations again for the clearcoat layer. Remember that
// the clearcoat can have its own roughness and its own normal.
let clearcoat_N = pbr_input.clearcoat_N;
lighting_input.layers[LAYER_CLEARCOAT].N = clearcoat_N;
lighting_input.layers[LAYER_CLEARCOAT].R = reflect(-V, clearcoat_N);
lighting_input.layers[LAYER_CLEARCOAT].NdotV = max(dot(clearcoat_N, V), 0.0001);
lighting_input.layers[LAYER_CLEARCOAT].perceptual_roughness = material.clearcoat_perceptual_roughness;
lighting_input.layers[LAYER_CLEARCOAT].roughness =
perceptualRoughnessToRoughness(material.clearcoat_perceptual_roughness);
lighting_input.clearcoat_strength = material.clearcoat;
#endif // STANDARD_MATERIAL_CLEARCOAT
#ifdef STANDARD_MATERIAL_ANISOTROPY
lighting_input.anisotropy = pbr_input.anisotropy_strength;
lighting_input.Ta = pbr_input.anisotropy_T;
lighting_input.Ba = pbr_input.anisotropy_B;
#endif // STANDARD_MATERIAL_ANISOTROPY
return lighting_input;
}
// Diffuse strength is inversely related to metallicity, specular and diffuse transmission
fn calculate_diffuse_color(
base_color: vec3<f32>,
metallic: f32,
specular_transmission: f32,
diffuse_transmission: f32
) -> vec3<f32> {
return base_color * (1.0 - metallic) * (1.0 - specular_transmission) *
(1.0 - diffuse_transmission);
}
// Remapping [0,1] reflectance to F0
// See https://google.github.io/filament/Filament.html#materialsystem/parameterization/remapping
fn calculate_F0(base_color: vec3<f32>, metallic: f32, reflectance: vec3<f32>) -> vec3<f32> {
return 0.16 * reflectance * reflectance * (1.0 - metallic) + base_color * metallic;
}
// Specular BRDF // Specular BRDF
// https://google.github.io/filament/Filament.html#materialsystem/specularbrdf // https://google.github.io/filament/Filament.html#materialsystem/specularbrdf

View File

@ -10,7 +10,6 @@
mesh_view_bindings::{view, depth_prepass_texture, deferred_prepass_texture, ssr_settings}, mesh_view_bindings::{view, depth_prepass_texture, deferred_prepass_texture, ssr_settings},
pbr_deferred_functions::pbr_input_from_deferred_gbuffer, pbr_deferred_functions::pbr_input_from_deferred_gbuffer,
pbr_deferred_types, pbr_deferred_types,
pbr_functions,
prepass_utils, prepass_utils,
raymarch::{ raymarch::{
depth_ray_march_from_cs, depth_ray_march_from_cs,
@ -99,19 +98,19 @@ fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {
return fragment; return fragment;
} }
// Unpack the PBR input. #ifdef ENVIRONMENT_MAP
var specular_occlusion = pbr_input.specular_occlusion; var lighting_input = lighting::pbr_input_to_lighting_input(pbr_input);
let world_position = pbr_input.world_position.xyz; let R = lighting_input.layers[LAYER_BASE].R;
let N = pbr_input.N; #else // ENVIRONMENT_MAP
let V = pbr_input.V; let R = reflect(-pbr_input.V, pbr_input.N);
#endif // ENVIRONMENT_MAP
// Calculate the reflection vector.
let R = reflect(-V, N);
// Do the raymarching. // Do the raymarching.
let world_position = pbr_input.world_position.xyz;
let ssr_specular = evaluate_ssr(R, world_position); let ssr_specular = evaluate_ssr(R, world_position);
var indirect_light = ssr_specular.rgb; var indirect_light = ssr_specular.rgb;
specular_occlusion *= ssr_specular.a;
let specular_occlusion = pbr_input.specular_occlusion * ssr_specular.a;
// Sample the environment map if necessary. // Sample the environment map if necessary.
// //
@ -120,58 +119,6 @@ fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {
// //
// TODO: Merge this with the duplicated code in `apply_pbr_lighting`. // TODO: Merge this with the duplicated code in `apply_pbr_lighting`.
#ifdef ENVIRONMENT_MAP #ifdef ENVIRONMENT_MAP
// Unpack values required for environment mapping.
let base_color = pbr_input.material.base_color.rgb;
let metallic = pbr_input.material.metallic;
let reflectance = pbr_input.material.reflectance;
let specular_transmission = pbr_input.material.specular_transmission;
let diffuse_transmission = pbr_input.material.diffuse_transmission;
let diffuse_occlusion = pbr_input.diffuse_occlusion;
#ifdef STANDARD_MATERIAL_CLEARCOAT
// Do the above calculations again for the clearcoat layer. Remember that
// the clearcoat can have its own roughness and its own normal.
let clearcoat = pbr_input.material.clearcoat;
let clearcoat_perceptual_roughness = pbr_input.material.clearcoat_perceptual_roughness;
let clearcoat_roughness = lighting::perceptualRoughnessToRoughness(clearcoat_perceptual_roughness);
let clearcoat_N = pbr_input.clearcoat_N;
let clearcoat_NdotV = max(dot(clearcoat_N, pbr_input.V), 0.0001);
let clearcoat_R = reflect(-pbr_input.V, clearcoat_N);
#endif // STANDARD_MATERIAL_CLEARCOAT
// Calculate various other values needed for environment mapping.
let roughness = lighting::perceptualRoughnessToRoughness(perceptual_roughness);
let diffuse_color = pbr_functions::calculate_diffuse_color(
base_color,
metallic,
specular_transmission,
diffuse_transmission
);
let NdotV = max(dot(N, V), 0.0001);
let F_ab = lighting::F_AB(perceptual_roughness, NdotV);
let F0 = pbr_functions::calculate_F0(base_color, metallic, reflectance);
// Pack all the values into a structure.
var lighting_input: lighting::LightingInput;
lighting_input.layers[LAYER_BASE].NdotV = NdotV;
lighting_input.layers[LAYER_BASE].N = N;
lighting_input.layers[LAYER_BASE].R = R;
lighting_input.layers[LAYER_BASE].perceptual_roughness = perceptual_roughness;
lighting_input.layers[LAYER_BASE].roughness = roughness;
lighting_input.P = world_position.xyz;
lighting_input.V = V;
lighting_input.diffuse_color = diffuse_color;
lighting_input.F0_ = F0;
lighting_input.F_ab = F_ab;
#ifdef STANDARD_MATERIAL_CLEARCOAT
lighting_input.layers[LAYER_CLEARCOAT].NdotV = clearcoat_NdotV;
lighting_input.layers[LAYER_CLEARCOAT].N = clearcoat_N;
lighting_input.layers[LAYER_CLEARCOAT].R = clearcoat_R;
lighting_input.layers[LAYER_CLEARCOAT].perceptual_roughness = clearcoat_perceptual_roughness;
lighting_input.layers[LAYER_CLEARCOAT].roughness = clearcoat_roughness;
lighting_input.clearcoat_strength = clearcoat;
#endif // STANDARD_MATERIAL_CLEARCOAT
// Determine which cluster we're in. We'll need this to find the right // Determine which cluster we're in. We'll need this to find the right
// reflection probe. // reflection probe.
let cluster_index = clustered_forward::fragment_cluster_index( let cluster_index = clustered_forward::fragment_cluster_index(
@ -185,9 +132,9 @@ fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {
// Accumulate the environment map light. // Accumulate the environment map light.
indirect_light += view.exposure * indirect_light += view.exposure *
(environment_light.diffuse * diffuse_occlusion + (environment_light.diffuse * pbr_input.diffuse_occlusion +
environment_light.specular * specular_occlusion); environment_light.specular * specular_occlusion);
#endif #endif // ENVIRONMENT_MAP
// Write the results. // Write the results.
return vec4(fragment.rgb + indirect_light, 1.0); return vec4(fragment.rgb + indirect_light, 1.0);