diff --git a/crates/bevy_pbr/src/entity.rs b/crates/bevy_pbr/src/entity.rs index d8afaa1506034..32c7462faccf8 100644 --- a/crates/bevy_pbr/src/entity.rs +++ b/crates/bevy_pbr/src/entity.rs @@ -40,6 +40,11 @@ impl Default for PbrComponents { bind_group: 3, binding: 0, }, + // StandardMaterial_pbr + DynamicBinding { + bind_group: 3, + binding: 3, + }, ], ..Default::default() }, diff --git a/crates/bevy_pbr/src/light.rs b/crates/bevy_pbr/src/light.rs index 47f238df167fc..b6768129635bd 100644 --- a/crates/bevy_pbr/src/light.rs +++ b/crates/bevy_pbr/src/light.rs @@ -14,14 +14,16 @@ pub struct Light { pub color: Color, pub fov: f32, pub depth: Range, + pub attenuation: f32, } impl Default for Light { fn default() -> Self { Light { - color: Color::rgb(1.0, 1.0, 1.0), + color: Color::rgba(1.0, 1.0, 1.0, 100.0), depth: 0.1..50.0, fov: f32::to_radians(60.0), + attenuation: 100.0, } } } @@ -49,7 +51,7 @@ impl LightRaw { let (x, y, z) = translation.0.into(); LightRaw { proj: proj.to_cols_array_2d(), - pos: [x, y, z, 1.0], + pos: [x, y, z, light.attenuation], // pos.w is the attenuation. color: light.color.into(), } } diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 378d4dcbd9c83..6385be3a8f664 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -1,10 +1,13 @@ use bevy_asset::{self, Handle}; -use bevy_render::{color::Color, renderer::RenderResources, shader::ShaderDefs, texture::Texture}; +use bevy_render::{color::Color, renderer::{RenderResources}, shader::ShaderDefs, texture::Texture}; +use bevy_math::Vec2; /// A material with "standard" properties used in PBR lighting #[derive(RenderResources, ShaderDefs)] pub struct StandardMaterial { pub albedo: Color, + /// Represented as roughness/metallic. + pub pbr: Vec2, #[shader_def] pub albedo_texture: Option>, #[render_resources(ignore)] @@ -16,6 +19,7 @@ impl Default for StandardMaterial { fn default() -> Self { StandardMaterial { albedo: Color::rgb(1.0, 1.0, 1.0), + pbr: Vec2::new(0.01, 0.08), albedo_texture: None, shaded: true, } diff --git a/crates/bevy_pbr/src/render_graph/forward_pipeline/forward.frag b/crates/bevy_pbr/src/render_graph/forward_pipeline/forward.frag index 9c869f29e7129..7baaf8534215c 100644 --- a/crates/bevy_pbr/src/render_graph/forward_pipeline/forward.frag +++ b/crates/bevy_pbr/src/render_graph/forward_pipeline/forward.frag @@ -4,18 +4,22 @@ const int MAX_LIGHTS = 10; struct Light { mat4 proj; - vec4 pos; + vec3 pos; + float attenuation; vec4 color; }; layout(location = 0) in vec3 v_Position; layout(location = 1) in vec3 v_Normal; layout(location = 2) in vec2 v_Uv; +layout(location = 3) in vec3 w_Position; + layout(location = 0) out vec4 o_Target; layout(set = 0, binding = 0) uniform Camera { mat4 ViewProj; + vec4 CameraPos; }; layout(set = 1, binding = 0) uniform Lights { @@ -27,13 +31,97 @@ layout(set = 3, binding = 0) uniform StandardMaterial_albedo { vec4 Albedo; }; +layout(set = 3, binding = 3) uniform StandardMaterial_pbr { + vec2 pbr; +}; + # ifdef STANDARDMATERIAL_ALBEDO_TEXTURE layout(set = 3, binding = 1) uniform texture2D StandardMaterial_albedo_texture; layout(set = 3, binding = 2) uniform sampler StandardMaterial_albedo_texture_sampler; # endif +# ifdef STANDARDMATERIAL_SHADED + +#define saturate(x) clamp(x, 0.0, 1.0) +const float PI = 3.141592653589793; + +float pow5(float x) { + float x2 = x * x; + return x2 * x2 * x; +} + +float getSquareFalloffAttenuation(float distanceSquare, float falloff) { + float factor = distanceSquare * falloff; + float smoothFactor = saturate(1.0 - factor * factor); + return smoothFactor * smoothFactor; +} + +float getDistanceAttenuation(const highp vec3 posToLight, float falloff) { + float distanceSquare = dot(posToLight, posToLight); + float attenuation = getSquareFalloffAttenuation(distanceSquare, falloff); + return attenuation * 1.0 / max(distanceSquare, 1e-4); +} + +float D_GGX(float roughness, float NoH, const vec3 h) { + float oneMinusNoHSquared = 1.0 - NoH * NoH; + float a = NoH * roughness; + float k = roughness / (oneMinusNoHSquared + a * a); + float d = k * k * (1.0 / PI); + return d; +} + +float V_SmithGGXCorrelated(float roughness, float NoV, float NoL) { + float a2 = roughness * roughness; + float lambdaV = NoL * sqrt((NoV - a2 * NoV) * NoV + a2); + float lambdaL = NoV * sqrt((NoL - a2 * NoL) * NoL + a2); + float v = 0.5 / (lambdaV + lambdaL); + return v; +} + +vec3 F_Schlick(const vec3 f0, float f90, float VoH) { + return f0 + (f90 - f0) * pow5(1.0 - VoH); +} + +float F_Schlick(float f0, float f90, float VoH) { + return f0 + (f90 - f0) * pow5(1.0 - VoH); +} + +vec3 fresnel(vec3 f0, float LoH) { + float f90 = saturate(dot(f0, vec3(50.0 * 0.33))); + return F_Schlick(f0, f90, LoH); +} + +vec3 isotropicLobe(vec3 f0, float roughness, const vec3 h, float NoV, float NoL, float NoH, float LoH) { + + float D = D_GGX(roughness, NoH, h); + float V = V_SmithGGXCorrelated(roughness, NoV, NoL); + vec3 F = fresnel(f0, LoH); + + return (D * V) * F; +} + +float Fd_Burley(float roughness, float NoV, float NoL, float LoH) { + float f90 = 0.5 + 2.0 * roughness * LoH * LoH; + float lightScatter = F_Schlick(1.0, f90, NoL); + float viewScatter = F_Schlick(1.0, f90, NoV); + return lightScatter * viewScatter * (1.0 / PI); +} + +vec3 computeDiffuseColor(const vec3 baseColor, float metallic) { + return baseColor * (1.0 - metallic); +} + +#define MIN_N_DOT_V 1e-4 + +float clampNoV(float NoV) { + // Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886" + return max(NoV, MIN_N_DOT_V); +} + +# endif + void main() { - vec4 output_color = Albedo; + vec4 output_color = vec4(1.0, 0.0, 0.0, 1.0); //Albedo; # ifdef STANDARDMATERIAL_ALBEDO_TEXTURE output_color *= texture( sampler2D(StandardMaterial_albedo_texture, StandardMaterial_albedo_texture_sampler), @@ -41,19 +129,45 @@ void main() { # endif # ifdef STANDARDMATERIAL_SHADED - vec3 normal = normalize(v_Normal); - vec3 ambient = vec3(0.05, 0.05, 0.05); + float roughness = pbr.x; + float metallic = pbr.y; + vec3 N = normalize(v_Normal); + vec3 V = normalize(CameraPos.xyz - v_Position.xyz); + + vec3 F0 = vec3(0.04); + F0 = mix(F0, output_color.rgb, metallic); + + vec3 diffuseColor = computeDiffuseColor(output_color.rgb, metallic); + // accumulate color - vec3 color = ambient; + vec3 light_accum = vec3(0.0); for (int i=0; i, - query: Query<(&Camera, &Transform)>, + query: Query<(&Camera, &Transform, &Translation)>, ) { let render_resource_context = &**render_resource_context; - let (camera, transform) = if let Some(camera_entity) = active_cameras.get(&state.camera_name) { + let (camera, transform, translation) = if let Some(camera_entity) = active_cameras.get(&state.camera_name) { + let camera = query.get::(camera_entity).unwrap(); + let transform = query.get::(camera_entity).unwrap(); + let translation = query.get::(camera_entity).unwrap(); + ( - query.get::(camera_entity).unwrap(), - query.get::(camera_entity).unwrap(), + camera, + transform, + translation, ) } else { return; @@ -90,7 +95,7 @@ pub fn camera_node_system( render_resource_context.map_buffer(staging_buffer); staging_buffer } else { - let size = std::mem::size_of::<[[f32; 4]; 4]>(); + let size = std::mem::size_of::<[[f32; 4]; 5]>(); let buffer = render_resource_context.create_buffer(BufferInfo { size, buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM, @@ -116,15 +121,16 @@ pub fn camera_node_system( staging_buffer }; - let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>(); - let camera_matrix: [f32; 16] = - (camera.projection_matrix * transform.value.inverse()).to_cols_array(); + let matrix_size = std::mem::size_of::<[[f32; 4]; 5]>(); + let mut camera_matrix_array: Vec = (camera.projection_matrix * transform.value.inverse()).to_cols_array().to_vec(); + camera_matrix_array.extend_from_slice(&[translation.x(), translation.y(), translation.z(), 1.0]); + let camera_gpu_data = camera_matrix_array.as_slice(); render_resource_context.write_mapped_buffer( staging_buffer, 0..matrix_size as u64, &mut |data, _renderer| { - data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes()); + data[0..matrix_size].copy_from_slice(camera_gpu_data.as_bytes()); }, ); render_resource_context.unmap_buffer(staging_buffer); diff --git a/crates/bevy_render/src/render_graph/nodes/pass_node.rs b/crates/bevy_render/src/render_graph/nodes/pass_node.rs index 56089d8e9c3e8..efc7d46440529 100644 --- a/crates/bevy_render/src/render_graph/nodes/pass_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/pass_node.rs @@ -77,7 +77,7 @@ impl PassNode { index: 0, bind_type: BindType::Uniform { dynamic: false, - properties: vec![UniformProperty::Struct(vec![UniformProperty::Mat4])], + properties: vec![UniformProperty::Struct(vec![UniformProperty::Mat4, UniformProperty::Vec4])], }, shader_stage: BindingShaderStage::VERTEX | BindingShaderStage::FRAGMENT, }], diff --git a/crates/bevy_render/src/shader/shader_reflect.rs b/crates/bevy_render/src/shader/shader_reflect.rs index 86bc07c611832..bec03f36e9306 100644 --- a/crates/bevy_render/src/shader/shader_reflect.rs +++ b/crates/bevy_render/src/shader/shader_reflect.rs @@ -356,6 +356,7 @@ mod tests { layout(location = 0) out vec4 v_Position; layout(set = 0, binding = 0) uniform Camera { mat4 ViewProj; + vec4 CameraPos; }; layout(set = 1, binding = 0) uniform texture2D Texture; @@ -451,6 +452,7 @@ mod tests { layout(location = 0) out vec4 v_Position; layout(set = 0, binding = 0) uniform Camera { mat4 ViewProj; + vec4 CameraPos; }; layout(set = 1, binding = 0) uniform texture2D Texture; diff --git a/crates/bevy_sprite/src/render/sprite.vert b/crates/bevy_sprite/src/render/sprite.vert index c4ecaed96e9bb..4e67a7099cebb 100644 --- a/crates/bevy_sprite/src/render/sprite.vert +++ b/crates/bevy_sprite/src/render/sprite.vert @@ -8,6 +8,7 @@ layout(location = 0) out vec2 v_Uv; layout(set = 0, binding = 0) uniform Camera { mat4 ViewProj; + vec4 CameraPos; }; layout(set = 2, binding = 0) uniform Transform { diff --git a/crates/bevy_sprite/src/render/sprite_sheet.vert b/crates/bevy_sprite/src/render/sprite_sheet.vert index d967ac5411ba3..fdc5086d8832d 100644 --- a/crates/bevy_sprite/src/render/sprite_sheet.vert +++ b/crates/bevy_sprite/src/render/sprite_sheet.vert @@ -9,6 +9,7 @@ layout(location = 1) out vec4 v_Color; layout(set = 0, binding = 0) uniform Camera { mat4 ViewProj; + vec4 CameraPos; }; // TODO: merge dimensions into "sprites" buffer when that is supported in the Uniforms derive abstraction diff --git a/crates/bevy_ui/src/render/ui.vert b/crates/bevy_ui/src/render/ui.vert index 2268af642b305..d9eef52f4fd61 100644 --- a/crates/bevy_ui/src/render/ui.vert +++ b/crates/bevy_ui/src/render/ui.vert @@ -8,6 +8,7 @@ layout(location = 0) out vec2 v_Uv; layout(set = 0, binding = 0) uniform Camera { mat4 ViewProj; + vec4 CameraPos; }; layout(set = 1, binding = 0) uniform Transform { diff --git a/examples/3d/msaa.rs b/examples/3d/msaa.rs index fa70a2deaa7f4..835495913552b 100644 --- a/examples/3d/msaa.rs +++ b/examples/3d/msaa.rs @@ -21,13 +21,13 @@ fn setup( commands // cube .spawn(PbrComponents { - mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })), + mesh: meshes.add(Mesh::from(shape::Icosphere { radius: 1.0, subdivisions: 32, })), material: materials.add(Color::rgb(0.5, 0.4, 0.3).into()), ..Default::default() }) // light .spawn(LightComponents { - translation: Translation::new(4.0, 8.0, 4.0), + translation: Translation::new(40.0, 80.0, 40.0), ..Default::default() }) // camera diff --git a/examples/shader/shader_custom_material.rs b/examples/shader/shader_custom_material.rs index f672eca94ce10..198d3bb293489 100644 --- a/examples/shader/shader_custom_material.rs +++ b/examples/shader/shader_custom_material.rs @@ -28,6 +28,7 @@ const VERTEX_SHADER: &str = r#" layout(location = 0) in vec3 Vertex_Position; layout(set = 0, binding = 0) uniform Camera { mat4 ViewProj; + vec4 CameraPos; }; layout(set = 1, binding = 0) uniform Transform { mat4 Model; diff --git a/examples/shader/shader_defs.rs b/examples/shader/shader_defs.rs index 79b10cf19e751..fc1e35a577915 100644 --- a/examples/shader/shader_defs.rs +++ b/examples/shader/shader_defs.rs @@ -36,6 +36,7 @@ const VERTEX_SHADER: &str = r#" layout(location = 0) in vec3 Vertex_Position; layout(set = 0, binding = 0) uniform Camera { mat4 ViewProj; + vec4 CameraPos; }; layout(set = 1, binding = 0) uniform Transform { mat4 Model;