mirror of
https://github.com/bevyengine/bevy
synced 2024-11-21 20:23:28 +00:00
parent
a2cac6a0d5
commit
326b20643f
11 changed files with 640 additions and 67 deletions
|
@ -146,6 +146,10 @@ path = "examples/3d/3d_scene.rs"
|
|||
name = "3d_scene_pipelined"
|
||||
path = "examples/3d/3d_scene_pipelined.rs"
|
||||
|
||||
[[example]]
|
||||
name = "cornell_box_pipelined"
|
||||
path = "examples/3d/cornell_box_pipelined.rs"
|
||||
|
||||
[[example]]
|
||||
name = "load_gltf"
|
||||
path = "examples/3d/load_gltf.rs"
|
||||
|
|
|
@ -169,7 +169,7 @@ impl GlobalTransform {
|
|||
#[doc(hidden)]
|
||||
#[inline]
|
||||
pub fn rotate(&mut self, rotation: Quat) {
|
||||
self.rotation *= rotation;
|
||||
self.rotation = rotation * self.rotation;
|
||||
}
|
||||
|
||||
/// Multiplies `self` with `transform` component by component, returning the
|
||||
|
|
|
@ -181,7 +181,7 @@ impl Transform {
|
|||
/// Rotates the transform by the given rotation.
|
||||
#[inline]
|
||||
pub fn rotate(&mut self, rotation: Quat) {
|
||||
self.rotation *= rotation;
|
||||
self.rotation = rotation * self.rotation;
|
||||
}
|
||||
|
||||
/// Multiplies `self` with `transform` component by component, returning the
|
||||
|
|
|
@ -42,6 +42,7 @@ macro_rules! glam_vectors {
|
|||
}
|
||||
|
||||
glam_vectors! {
|
||||
glam::UVec4, UVec4, (x, y, z, w),
|
||||
glam::Vec2, Vec2, (x, y),
|
||||
glam::Vec3, Vec3, (x, y, z),
|
||||
glam::Vec4, Vec4, (x, y, z, w),
|
||||
|
|
|
@ -4,10 +4,13 @@ use bevy::{
|
|||
ecs::prelude::*,
|
||||
input::Input,
|
||||
math::{Quat, Vec3},
|
||||
pbr2::{PbrBundle, PointLight, PointLightBundle, StandardMaterial},
|
||||
pbr2::{
|
||||
AmbientLight, DirectionalLight, DirectionalLightBundle, PbrBundle, PointLight,
|
||||
PointLightBundle, StandardMaterial,
|
||||
},
|
||||
prelude::{App, Assets, BuildChildren, KeyCode, Transform},
|
||||
render2::{
|
||||
camera::PerspectiveCameraBundle,
|
||||
camera::{OrthographicProjection, PerspectiveCameraBundle},
|
||||
color::Color,
|
||||
mesh::{shape, Mesh},
|
||||
},
|
||||
|
@ -21,6 +24,7 @@ fn main() {
|
|||
.add_plugin(LogDiagnosticsPlugin::default())
|
||||
.add_startup_system(setup.system())
|
||||
.add_system(movement.system())
|
||||
.add_system(animate_light_direction.system())
|
||||
.run();
|
||||
}
|
||||
|
||||
|
@ -32,11 +36,15 @@ fn setup(
|
|||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
) {
|
||||
commands.insert_resource(AmbientLight {
|
||||
color: Color::ORANGE_RED,
|
||||
brightness: 0.02,
|
||||
});
|
||||
// plane
|
||||
commands.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Plane { size: 5.0 })),
|
||||
mesh: meshes.add(Mesh::from(shape::Plane { size: 10.0 })),
|
||||
material: materials.add(StandardMaterial {
|
||||
base_color: Color::INDIGO,
|
||||
base_color: Color::WHITE,
|
||||
perceptual_roughness: 1.0,
|
||||
..Default::default()
|
||||
}),
|
||||
|
@ -46,7 +54,7 @@ fn setup(
|
|||
let mut transform = Transform::from_xyz(2.5, 2.5, 0.0);
|
||||
transform.rotate(Quat::from_rotation_z(std::f32::consts::FRAC_PI_2));
|
||||
commands.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Plane { size: 5.0 })),
|
||||
mesh: meshes.add(Mesh::from(shape::Box::new(5.0, 0.15, 5.0))),
|
||||
transform,
|
||||
material: materials.add(StandardMaterial {
|
||||
base_color: Color::INDIGO,
|
||||
|
@ -59,7 +67,7 @@ fn setup(
|
|||
let mut transform = Transform::from_xyz(0.0, 2.5, -2.5);
|
||||
transform.rotate(Quat::from_rotation_x(std::f32::consts::FRAC_PI_2));
|
||||
commands.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Plane { size: 5.0 })),
|
||||
mesh: meshes.add(Mesh::from(shape::Box::new(5.0, 0.15, 5.0))),
|
||||
transform,
|
||||
material: materials.add(StandardMaterial {
|
||||
base_color: Color::INDIGO,
|
||||
|
@ -76,7 +84,7 @@ fn setup(
|
|||
base_color: Color::PINK,
|
||||
..Default::default()
|
||||
}),
|
||||
transform: Transform::from_xyz(0.0, 1.0, 0.0),
|
||||
transform: Transform::from_xyz(0.0, 0.5, 0.0),
|
||||
..Default::default()
|
||||
})
|
||||
.insert(Movable);
|
||||
|
@ -174,12 +182,43 @@ fn setup(
|
|||
});
|
||||
});
|
||||
|
||||
// camera
|
||||
commands.spawn_bundle(PerspectiveCameraBundle {
|
||||
transform: Transform::from_xyz(-2.0, 5.0, 7.5)
|
||||
.looking_at(Vec3::new(0.0, 2.0, 0.0), Vec3::Y),
|
||||
const HALF_SIZE: f32 = 10.0;
|
||||
commands.spawn_bundle(DirectionalLightBundle {
|
||||
directional_light: DirectionalLight {
|
||||
// Configure the projection to better fit the scene
|
||||
shadow_projection: OrthographicProjection {
|
||||
left: -HALF_SIZE,
|
||||
right: HALF_SIZE,
|
||||
bottom: -HALF_SIZE,
|
||||
top: HALF_SIZE,
|
||||
near: -10.0 * HALF_SIZE,
|
||||
far: 10.0 * HALF_SIZE,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
transform: Transform {
|
||||
translation: Vec3::new(0.0, 2.0, 0.0),
|
||||
rotation: Quat::from_rotation_x(-1.2),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
// camera
|
||||
commands.spawn_bundle(PerspectiveCameraBundle {
|
||||
transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
fn animate_light_direction(
|
||||
time: Res<Time>,
|
||||
mut query: Query<&mut Transform, With<DirectionalLight>>,
|
||||
) {
|
||||
for mut transform in query.iter_mut() {
|
||||
transform.rotate(Quat::from_rotation_y(time.delta_seconds() * 0.5));
|
||||
}
|
||||
}
|
||||
|
||||
fn movement(
|
||||
|
|
178
examples/3d/cornell_box_pipelined.rs
Normal file
178
examples/3d/cornell_box_pipelined.rs
Normal file
|
@ -0,0 +1,178 @@
|
|||
use bevy::{
|
||||
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
||||
ecs::prelude::*,
|
||||
math::{Mat4, Quat, Vec3},
|
||||
pbr2::{
|
||||
AmbientLight, DirectionalLight, DirectionalLightBundle, PbrBundle, PointLight,
|
||||
PointLightBundle, StandardMaterial,
|
||||
},
|
||||
prelude::{App, Assets, BuildChildren, Transform},
|
||||
render2::{
|
||||
camera::{OrthographicProjection, PerspectiveCameraBundle},
|
||||
color::Color,
|
||||
mesh::{shape, Mesh},
|
||||
},
|
||||
PipelinedDefaultPlugins,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(PipelinedDefaultPlugins)
|
||||
.add_plugin(FrameTimeDiagnosticsPlugin::default())
|
||||
.add_plugin(LogDiagnosticsPlugin::default())
|
||||
.add_startup_system(setup.system())
|
||||
.run();
|
||||
}
|
||||
|
||||
/// set up a simple 3D scene
|
||||
fn setup(
|
||||
mut commands: Commands,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
) {
|
||||
let box_size = 2.0;
|
||||
let box_thickness = 0.15;
|
||||
let box_offset = (box_size + box_thickness) / 2.0;
|
||||
|
||||
// left - red
|
||||
let mut transform = Transform::from_xyz(-box_offset, box_offset, 0.0);
|
||||
transform.rotate(Quat::from_rotation_z(std::f32::consts::FRAC_PI_2));
|
||||
commands.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Box::new(
|
||||
box_size,
|
||||
box_thickness,
|
||||
box_size,
|
||||
))),
|
||||
transform,
|
||||
material: materials.add(StandardMaterial {
|
||||
base_color: Color::rgb(0.63, 0.065, 0.05),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
});
|
||||
// right - green
|
||||
let mut transform = Transform::from_xyz(box_offset, box_offset, 0.0);
|
||||
transform.rotate(Quat::from_rotation_z(std::f32::consts::FRAC_PI_2));
|
||||
commands.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Box::new(
|
||||
box_size,
|
||||
box_thickness,
|
||||
box_size,
|
||||
))),
|
||||
transform,
|
||||
material: materials.add(StandardMaterial {
|
||||
base_color: Color::rgb(0.14, 0.45, 0.091),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
});
|
||||
// bottom - white
|
||||
commands.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Box::new(
|
||||
box_size + 2.0 * box_thickness,
|
||||
box_thickness,
|
||||
box_size,
|
||||
))),
|
||||
material: materials.add(StandardMaterial {
|
||||
base_color: Color::rgb(0.725, 0.71, 0.68),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
});
|
||||
// top - white
|
||||
let transform = Transform::from_xyz(0.0, 2.0 * box_offset, 0.0);
|
||||
commands.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Box::new(
|
||||
box_size + 2.0 * box_thickness,
|
||||
box_thickness,
|
||||
box_size,
|
||||
))),
|
||||
transform,
|
||||
material: materials.add(StandardMaterial {
|
||||
base_color: Color::rgb(0.725, 0.71, 0.68),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
});
|
||||
// back - white
|
||||
let mut transform = Transform::from_xyz(0.0, box_offset, -box_offset);
|
||||
transform.rotate(Quat::from_rotation_x(std::f32::consts::FRAC_PI_2));
|
||||
commands.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Box::new(
|
||||
box_size + 2.0 * box_thickness,
|
||||
box_thickness,
|
||||
box_size + 2.0 * box_thickness,
|
||||
))),
|
||||
transform,
|
||||
material: materials.add(StandardMaterial {
|
||||
base_color: Color::rgb(0.725, 0.71, 0.68),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
// ambient light
|
||||
commands.insert_resource(AmbientLight {
|
||||
color: Color::WHITE,
|
||||
brightness: 0.02,
|
||||
});
|
||||
// top light
|
||||
commands
|
||||
.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Plane { size: 0.4 })),
|
||||
transform: Transform::from_matrix(Mat4::from_scale_rotation_translation(
|
||||
Vec3::ONE,
|
||||
Quat::from_rotation_x(std::f32::consts::PI),
|
||||
Vec3::new(0.0, box_size + 0.5 * box_thickness, 0.0),
|
||||
)),
|
||||
material: materials.add(StandardMaterial {
|
||||
base_color: Color::WHITE,
|
||||
emissive: Color::WHITE * 100.0,
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
})
|
||||
.with_children(|builder| {
|
||||
builder.spawn_bundle(PointLightBundle {
|
||||
point_light: PointLight {
|
||||
color: Color::WHITE,
|
||||
shadow_bias_min: 0.00001,
|
||||
shadow_bias_max: 0.0001,
|
||||
intensity: 25.0,
|
||||
..Default::default()
|
||||
},
|
||||
transform: Transform::from_translation((box_thickness + 0.05) * Vec3::Y),
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
// directional light
|
||||
const HALF_SIZE: f32 = 10.0;
|
||||
commands
|
||||
.spawn_bundle(DirectionalLightBundle {
|
||||
directional_light: DirectionalLight {
|
||||
illuminance: 10000.0,
|
||||
shadow_bias_min: 0.00001,
|
||||
shadow_bias_max: 0.0001,
|
||||
shadow_projection: OrthographicProjection {
|
||||
left: -HALF_SIZE,
|
||||
right: HALF_SIZE,
|
||||
bottom: -HALF_SIZE,
|
||||
top: HALF_SIZE,
|
||||
near: -10.0 * HALF_SIZE,
|
||||
far: 10.0 * HALF_SIZE,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
transform: Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::PI / 2.0)),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
// camera
|
||||
commands
|
||||
.spawn_bundle(PerspectiveCameraBundle {
|
||||
transform: Transform::from_xyz(0.0, box_offset, 4.0)
|
||||
.looking_at(Vec3::new(0.0, box_offset, 0.0), Vec3::Y),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{PointLight, StandardMaterial};
|
||||
use crate::{DirectionalLight, PointLight, StandardMaterial};
|
||||
use bevy_asset::Handle;
|
||||
use bevy_ecs::bundle::Bundle;
|
||||
use bevy_render2::mesh::Mesh;
|
||||
|
@ -23,10 +23,18 @@ impl Default for PbrBundle {
|
|||
}
|
||||
}
|
||||
|
||||
/// A component bundle for "light" entities
|
||||
/// A component bundle for "point light" entities
|
||||
#[derive(Debug, Bundle, Default)]
|
||||
pub struct PointLightBundle {
|
||||
pub point_light: PointLight,
|
||||
pub transform: Transform,
|
||||
pub global_transform: GlobalTransform,
|
||||
}
|
||||
|
||||
/// A component bundle for "directional light" entities
|
||||
#[derive(Debug, Bundle, Default)]
|
||||
pub struct DirectionalLightBundle {
|
||||
pub directional_light: DirectionalLight,
|
||||
pub transform: Transform,
|
||||
pub global_transform: GlobalTransform,
|
||||
}
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
use bevy_ecs::reflect::ReflectComponent;
|
||||
use bevy_reflect::Reflect;
|
||||
use bevy_render2::color::Color;
|
||||
use bevy_render2::{camera::OrthographicProjection, color::Color};
|
||||
|
||||
/// A light that emits light in all directions from a central point.
|
||||
#[derive(Debug, Clone, Copy, Reflect)]
|
||||
#[reflect(Component)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct PointLight {
|
||||
pub color: Color,
|
||||
pub intensity: f32,
|
||||
pub range: f32,
|
||||
pub radius: f32,
|
||||
pub shadow_bias_min: f32,
|
||||
pub shadow_bias_max: f32,
|
||||
}
|
||||
|
||||
impl Default for PointLight {
|
||||
|
@ -19,10 +18,78 @@ impl Default for PointLight {
|
|||
intensity: 200.0,
|
||||
range: 20.0,
|
||||
radius: 0.0,
|
||||
shadow_bias_min: Self::DEFAULT_SHADOW_BIAS_MIN,
|
||||
shadow_bias_max: Self::DEFAULT_SHADOW_BIAS_MAX,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PointLight {
|
||||
pub const DEFAULT_SHADOW_BIAS_MIN: f32 = 0.00005;
|
||||
pub const DEFAULT_SHADOW_BIAS_MAX: f32 = 0.002;
|
||||
}
|
||||
|
||||
/// A Directional light.
|
||||
///
|
||||
/// Directional lights don't exist in reality but they are a good
|
||||
/// approximation for light sources VERY far away, like the sun or
|
||||
/// the moon.
|
||||
///
|
||||
/// Valid values for `illuminance` are:
|
||||
///
|
||||
/// | Illuminance (lux) | Surfaces illuminated by |
|
||||
/// |-------------------|------------------------------------------------|
|
||||
/// | 0.0001 | Moonless, overcast night sky (starlight) |
|
||||
/// | 0.002 | Moonless clear night sky with airglow |
|
||||
/// | 0.05–0.3 | Full moon on a clear night |
|
||||
/// | 3.4 | Dark limit of civil twilight under a clear sky |
|
||||
/// | 20–50 | Public areas with dark surroundings |
|
||||
/// | 50 | Family living room lights |
|
||||
/// | 80 | Office building hallway/toilet lighting |
|
||||
/// | 100 | Very dark overcast day |
|
||||
/// | 150 | Train station platforms |
|
||||
/// | 320–500 | Office lighting |
|
||||
/// | 400 | Sunrise or sunset on a clear day. |
|
||||
/// | 1000 | Overcast day; typical TV studio lighting |
|
||||
/// | 10,000–25,000 | Full daylight (not direct sun) |
|
||||
/// | 32,000–100,000 | Direct sunlight |
|
||||
///
|
||||
/// Source: [Wikipedia](https://en.wikipedia.org/wiki/Lux)
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DirectionalLight {
|
||||
pub color: Color,
|
||||
pub illuminance: f32,
|
||||
pub shadow_projection: OrthographicProjection,
|
||||
pub shadow_bias_min: f32,
|
||||
pub shadow_bias_max: f32,
|
||||
}
|
||||
|
||||
impl Default for DirectionalLight {
|
||||
fn default() -> Self {
|
||||
let size = 100.0;
|
||||
DirectionalLight {
|
||||
color: Color::rgb(1.0, 1.0, 1.0),
|
||||
illuminance: 100000.0,
|
||||
shadow_projection: OrthographicProjection {
|
||||
left: -size,
|
||||
right: size,
|
||||
bottom: -size,
|
||||
top: size,
|
||||
near: -size,
|
||||
far: size,
|
||||
..Default::default()
|
||||
},
|
||||
shadow_bias_min: Self::DEFAULT_SHADOW_BIAS_MIN,
|
||||
shadow_bias_max: Self::DEFAULT_SHADOW_BIAS_MAX,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DirectionalLight {
|
||||
pub const DEFAULT_SHADOW_BIAS_MIN: f32 = 0.00005;
|
||||
pub const DEFAULT_SHADOW_BIAS_MAX: f32 = 0.002;
|
||||
}
|
||||
|
||||
// Ambient light color.
|
||||
#[derive(Debug)]
|
||||
pub struct AmbientLight {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::{AmbientLight, ExtractedMeshes, MeshMeta, PbrShaders, PointLight};
|
||||
use crate::{AmbientLight, DirectionalLight, ExtractedMeshes, MeshMeta, PbrShaders, PointLight};
|
||||
use bevy_ecs::{prelude::*, system::SystemState};
|
||||
use bevy_math::{const_vec3, Mat4, Vec3, Vec4};
|
||||
use bevy_render2::{
|
||||
camera::CameraProjection,
|
||||
color::Color,
|
||||
core_pipeline::Transparent3dPhase,
|
||||
mesh::Mesh,
|
||||
|
@ -28,11 +29,22 @@ pub struct ExtractedPointLight {
|
|||
range: f32,
|
||||
radius: f32,
|
||||
transform: GlobalTransform,
|
||||
shadow_bias_min: f32,
|
||||
shadow_bias_max: f32,
|
||||
}
|
||||
|
||||
pub struct ExtractedDirectionalLight {
|
||||
color: Color,
|
||||
illuminance: f32,
|
||||
direction: Vec3,
|
||||
projection: Mat4,
|
||||
shadow_bias_min: f32,
|
||||
shadow_bias_max: f32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, AsStd140, Default, Debug)]
|
||||
pub struct GpuLight {
|
||||
pub struct GpuPointLight {
|
||||
color: Vec4,
|
||||
// proj: Mat4,
|
||||
position: Vec3,
|
||||
|
@ -40,30 +52,51 @@ pub struct GpuLight {
|
|||
radius: f32,
|
||||
near: f32,
|
||||
far: f32,
|
||||
shadow_bias_min: f32,
|
||||
shadow_bias_max: f32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, AsStd140, Default, Debug)]
|
||||
pub struct GpuDirectionalLight {
|
||||
view_projection: Mat4,
|
||||
color: Vec4,
|
||||
dir_to_light: Vec3,
|
||||
shadow_bias_min: f32,
|
||||
shadow_bias_max: f32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, AsStd140)]
|
||||
pub struct GpuLights {
|
||||
// TODO: this comes first to work around a WGSL alignment issue. We need to solve this issue before releasing the renderer rework
|
||||
lights: [GpuLight; MAX_POINT_LIGHTS],
|
||||
point_lights: [GpuPointLight; MAX_POINT_LIGHTS],
|
||||
directional_lights: [GpuDirectionalLight; MAX_DIRECTIONAL_LIGHTS],
|
||||
ambient_color: Vec4,
|
||||
len: u32,
|
||||
n_point_lights: u32,
|
||||
n_directional_lights: u32,
|
||||
}
|
||||
|
||||
// NOTE: this must be kept in sync MAX_POINT_LIGHTS in pbr.frag
|
||||
// NOTE: this must be kept in sync with the same constants in pbr.frag
|
||||
pub const MAX_POINT_LIGHTS: usize = 10;
|
||||
pub const SHADOW_SIZE: Extent3d = Extent3d {
|
||||
pub const MAX_DIRECTIONAL_LIGHTS: usize = 1;
|
||||
pub const POINT_SHADOW_SIZE: Extent3d = Extent3d {
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
depth_or_array_layers: 6 * MAX_POINT_LIGHTS as u32,
|
||||
depth_or_array_layers: (6 * MAX_POINT_LIGHTS) as u32,
|
||||
};
|
||||
pub const DIRECTIONAL_SHADOW_SIZE: Extent3d = Extent3d {
|
||||
width: 4096,
|
||||
height: 4096,
|
||||
depth_or_array_layers: MAX_DIRECTIONAL_LIGHTS as u32,
|
||||
};
|
||||
pub const SHADOW_FORMAT: TextureFormat = TextureFormat::Depth32Float;
|
||||
|
||||
pub struct ShadowShaders {
|
||||
pub pipeline: RenderPipeline,
|
||||
pub view_layout: BindGroupLayout,
|
||||
pub light_sampler: Sampler,
|
||||
pub point_light_sampler: Sampler,
|
||||
pub directional_light_sampler: Sampler,
|
||||
}
|
||||
|
||||
// TODO: this pattern for initializing the shaders / pipeline isn't ideal. this should be handled by the asset system
|
||||
|
@ -160,7 +193,17 @@ impl FromWorld for ShadowShaders {
|
|||
ShadowShaders {
|
||||
pipeline,
|
||||
view_layout,
|
||||
light_sampler: render_device.create_sampler(&SamplerDescriptor {
|
||||
point_light_sampler: render_device.create_sampler(&SamplerDescriptor {
|
||||
address_mode_u: AddressMode::ClampToEdge,
|
||||
address_mode_v: AddressMode::ClampToEdge,
|
||||
address_mode_w: AddressMode::ClampToEdge,
|
||||
mag_filter: FilterMode::Linear,
|
||||
min_filter: FilterMode::Linear,
|
||||
mipmap_filter: FilterMode::Nearest,
|
||||
compare: Some(CompareFunction::LessEqual),
|
||||
..Default::default()
|
||||
}),
|
||||
directional_light_sampler: render_device.create_sampler(&SamplerDescriptor {
|
||||
address_mode_u: AddressMode::ClampToEdge,
|
||||
address_mode_v: AddressMode::ClampToEdge,
|
||||
address_mode_w: AddressMode::ClampToEdge,
|
||||
|
@ -178,21 +221,36 @@ impl FromWorld for ShadowShaders {
|
|||
pub fn extract_lights(
|
||||
mut commands: Commands,
|
||||
ambient_light: Res<AmbientLight>,
|
||||
lights: Query<(Entity, &PointLight, &GlobalTransform)>,
|
||||
point_lights: Query<(Entity, &PointLight, &GlobalTransform)>,
|
||||
directional_lights: Query<(Entity, &DirectionalLight, &GlobalTransform)>,
|
||||
) {
|
||||
commands.insert_resource(ExtractedAmbientLight {
|
||||
color: ambient_light.color,
|
||||
brightness: ambient_light.brightness,
|
||||
});
|
||||
for (entity, light, transform) in lights.iter() {
|
||||
for (entity, point_light, transform) in point_lights.iter() {
|
||||
commands.get_or_spawn(entity).insert(ExtractedPointLight {
|
||||
color: light.color,
|
||||
intensity: light.intensity,
|
||||
range: light.range,
|
||||
radius: light.radius,
|
||||
color: point_light.color,
|
||||
intensity: point_light.intensity,
|
||||
range: point_light.range,
|
||||
radius: point_light.radius,
|
||||
transform: *transform,
|
||||
shadow_bias_min: point_light.shadow_bias_min,
|
||||
shadow_bias_max: point_light.shadow_bias_max,
|
||||
});
|
||||
}
|
||||
for (entity, directional_light, transform) in directional_lights.iter() {
|
||||
commands
|
||||
.get_or_spawn(entity)
|
||||
.insert(ExtractedDirectionalLight {
|
||||
color: directional_light.color,
|
||||
illuminance: directional_light.illuminance,
|
||||
direction: transform.forward(),
|
||||
projection: directional_light.shadow_projection.get_projection_matrix(),
|
||||
shadow_bias_min: directional_light.shadow_bias_min,
|
||||
shadow_bias_max: directional_light.shadow_bias_max,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Can't do `Vec3::Y * -1.0` because mul isn't const
|
||||
|
@ -239,13 +297,28 @@ const CUBE_MAP_FACES: [CubeMapFace; 6] = [
|
|||
},
|
||||
];
|
||||
|
||||
fn face_index_to_name(face_index: usize) -> &'static str {
|
||||
match face_index {
|
||||
0 => "+x",
|
||||
1 => "-x",
|
||||
2 => "+y",
|
||||
3 => "-y",
|
||||
4 => "+z",
|
||||
5 => "-z",
|
||||
_ => "invalid",
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ViewLight {
|
||||
pub depth_texture_view: TextureView,
|
||||
pub pass_name: String,
|
||||
}
|
||||
|
||||
pub struct ViewLights {
|
||||
pub light_depth_texture: Texture,
|
||||
pub light_depth_texture_view: TextureView,
|
||||
pub point_light_depth_texture: Texture,
|
||||
pub point_light_depth_texture_view: TextureView,
|
||||
pub directional_light_depth_texture: Texture,
|
||||
pub directional_light_depth_texture_view: TextureView,
|
||||
pub lights: Vec<Entity>,
|
||||
pub gpu_light_binding_index: u32,
|
||||
}
|
||||
|
@ -263,7 +336,8 @@ pub fn prepare_lights(
|
|||
mut light_meta: ResMut<LightMeta>,
|
||||
views: Query<Entity, With<RenderPhase<Transparent3dPhase>>>,
|
||||
ambient_light: Res<ExtractedAmbientLight>,
|
||||
lights: Query<&ExtractedPointLight>,
|
||||
point_lights: Query<&ExtractedPointLight>,
|
||||
directional_lights: Query<&ExtractedDirectionalLight>,
|
||||
) {
|
||||
// PERF: view.iter().count() could be views.iter().len() if we implemented ExactSizeIterator for archetype-only filters
|
||||
light_meta
|
||||
|
@ -273,10 +347,22 @@ pub fn prepare_lights(
|
|||
let ambient_color = ambient_light.color.as_rgba_linear() * ambient_light.brightness;
|
||||
// set up light data for each view
|
||||
for entity in views.iter() {
|
||||
let light_depth_texture = texture_cache.get(
|
||||
let point_light_depth_texture = texture_cache.get(
|
||||
&render_device,
|
||||
TextureDescriptor {
|
||||
size: SHADOW_SIZE,
|
||||
size: POINT_SHADOW_SIZE,
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: TextureDimension::D2,
|
||||
format: SHADOW_FORMAT,
|
||||
usage: TextureUsage::RENDER_ATTACHMENT | TextureUsage::SAMPLED,
|
||||
label: None,
|
||||
},
|
||||
);
|
||||
let directional_light_depth_texture = texture_cache.get(
|
||||
&render_device,
|
||||
TextureDescriptor {
|
||||
size: DIRECTIONAL_SHADOW_SIZE,
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: TextureDimension::D2,
|
||||
|
@ -289,12 +375,14 @@ pub fn prepare_lights(
|
|||
|
||||
let mut gpu_lights = GpuLights {
|
||||
ambient_color: ambient_color.into(),
|
||||
len: lights.iter().len() as u32,
|
||||
lights: [GpuLight::default(); MAX_POINT_LIGHTS],
|
||||
n_point_lights: point_lights.iter().len() as u32,
|
||||
n_directional_lights: directional_lights.iter().len() as u32,
|
||||
point_lights: [GpuPointLight::default(); MAX_POINT_LIGHTS],
|
||||
directional_lights: [GpuDirectionalLight::default(); MAX_DIRECTIONAL_LIGHTS],
|
||||
};
|
||||
|
||||
// TODO: this should select lights based on relevance to the view instead of the first ones that show up in a query
|
||||
for (light_index, light) in lights.iter().enumerate().take(MAX_POINT_LIGHTS) {
|
||||
for (light_index, light) in point_lights.iter().enumerate().take(MAX_POINT_LIGHTS) {
|
||||
let projection =
|
||||
Mat4::perspective_rh(std::f32::consts::FRAC_PI_2, 1.0, 0.1, light.range);
|
||||
|
||||
|
@ -308,7 +396,7 @@ pub fn prepare_lights(
|
|||
let view_rotation = GlobalTransform::identity().looking_at(*target, *up);
|
||||
|
||||
let depth_texture_view =
|
||||
light_depth_texture
|
||||
point_light_depth_texture
|
||||
.texture
|
||||
.create_view(&TextureViewDescriptor {
|
||||
label: None,
|
||||
|
@ -324,10 +412,17 @@ pub fn prepare_lights(
|
|||
let view_light_entity = commands
|
||||
.spawn()
|
||||
.insert_bundle((
|
||||
ViewLight { depth_texture_view },
|
||||
ViewLight {
|
||||
depth_texture_view,
|
||||
pass_name: format!(
|
||||
"shadow pass point light {} {}",
|
||||
light_index,
|
||||
face_index_to_name(face_index)
|
||||
),
|
||||
},
|
||||
ExtractedView {
|
||||
width: SHADOW_SIZE.width,
|
||||
height: SHADOW_SIZE.height,
|
||||
width: POINT_SHADOW_SIZE.width,
|
||||
height: POINT_SHADOW_SIZE.height,
|
||||
transform: view_translation * view_rotation,
|
||||
projection,
|
||||
},
|
||||
|
@ -337,7 +432,7 @@ pub fn prepare_lights(
|
|||
view_lights.push(view_light_entity);
|
||||
}
|
||||
|
||||
gpu_lights.lights[light_index] = GpuLight {
|
||||
gpu_lights.point_lights[light_index] = GpuPointLight {
|
||||
// premultiply color by intensity
|
||||
// we don't use the alpha at all, so no reason to multiply only [0..3]
|
||||
color: (light.color.as_rgba_linear() * light.intensity).into(),
|
||||
|
@ -347,11 +442,83 @@ pub fn prepare_lights(
|
|||
near: 0.1,
|
||||
far: light.range,
|
||||
// proj: projection,
|
||||
shadow_bias_min: light.shadow_bias_min,
|
||||
shadow_bias_max: light.shadow_bias_max,
|
||||
};
|
||||
}
|
||||
|
||||
let light_depth_texture_view =
|
||||
light_depth_texture
|
||||
for (i, light) in directional_lights
|
||||
.iter()
|
||||
.enumerate()
|
||||
.take(MAX_DIRECTIONAL_LIGHTS)
|
||||
{
|
||||
// direction is negated to be ready for N.L
|
||||
let dir_to_light = -light.direction;
|
||||
|
||||
// convert from illuminance (lux) to candelas
|
||||
//
|
||||
// exposure is hard coded at the moment but should be replaced
|
||||
// by values coming from the camera
|
||||
// see: https://google.github.io/filament/Filament.html#imagingpipeline/physicallybasedcamera/exposuresettings
|
||||
const APERTURE: f32 = 4.0;
|
||||
const SHUTTER_SPEED: f32 = 1.0 / 250.0;
|
||||
const SENSITIVITY: f32 = 100.0;
|
||||
let ev100 =
|
||||
f32::log2(APERTURE * APERTURE / SHUTTER_SPEED) - f32::log2(SENSITIVITY / 100.0);
|
||||
let exposure = 1.0 / (f32::powf(2.0, ev100) * 1.2);
|
||||
let intensity = light.illuminance * exposure;
|
||||
|
||||
// NOTE: A directional light seems to have to have an eye position on the line along the direction of the light
|
||||
// through the world origin. I (Rob Swain) do not yet understand why it cannot be translated away from this.
|
||||
let view = Mat4::look_at_rh(Vec3::ZERO, light.direction, Vec3::Y);
|
||||
// NOTE: This orthographic projection defines the volume within which shadows from a directional light can be cast
|
||||
let projection = light.projection;
|
||||
|
||||
gpu_lights.directional_lights[i] = GpuDirectionalLight {
|
||||
// premultiply color by intensity
|
||||
// we don't use the alpha at all, so no reason to multiply only [0..3]
|
||||
color: (light.color.as_rgba_linear() * intensity).into(),
|
||||
dir_to_light,
|
||||
// NOTE: * view is correct, it should not be view.inverse() here
|
||||
view_projection: projection * view,
|
||||
shadow_bias_min: light.shadow_bias_min,
|
||||
shadow_bias_max: light.shadow_bias_max,
|
||||
};
|
||||
|
||||
let depth_texture_view =
|
||||
directional_light_depth_texture
|
||||
.texture
|
||||
.create_view(&TextureViewDescriptor {
|
||||
label: None,
|
||||
format: None,
|
||||
dimension: Some(TextureViewDimension::D2),
|
||||
aspect: TextureAspect::All,
|
||||
base_mip_level: 0,
|
||||
mip_level_count: None,
|
||||
base_array_layer: i as u32,
|
||||
array_layer_count: NonZeroU32::new(1),
|
||||
});
|
||||
|
||||
let view_light_entity = commands
|
||||
.spawn()
|
||||
.insert_bundle((
|
||||
ViewLight {
|
||||
depth_texture_view,
|
||||
pass_name: format!("shadow pass directional light {}", i),
|
||||
},
|
||||
ExtractedView {
|
||||
width: DIRECTIONAL_SHADOW_SIZE.width,
|
||||
height: DIRECTIONAL_SHADOW_SIZE.height,
|
||||
transform: GlobalTransform::from_matrix(view.inverse()),
|
||||
projection,
|
||||
},
|
||||
RenderPhase::<ShadowPhase>::default(),
|
||||
))
|
||||
.id();
|
||||
view_lights.push(view_light_entity);
|
||||
}
|
||||
let point_light_depth_texture_view =
|
||||
point_light_depth_texture
|
||||
.texture
|
||||
.create_view(&TextureViewDescriptor {
|
||||
label: None,
|
||||
|
@ -363,10 +530,24 @@ pub fn prepare_lights(
|
|||
base_array_layer: 0,
|
||||
array_layer_count: None,
|
||||
});
|
||||
let directional_light_depth_texture_view = directional_light_depth_texture
|
||||
.texture
|
||||
.create_view(&TextureViewDescriptor {
|
||||
label: None,
|
||||
format: None,
|
||||
dimension: Some(TextureViewDimension::D2Array),
|
||||
aspect: TextureAspect::All,
|
||||
base_mip_level: 0,
|
||||
mip_level_count: None,
|
||||
base_array_layer: 0,
|
||||
array_layer_count: None,
|
||||
});
|
||||
|
||||
commands.entity(entity).insert(ViewLights {
|
||||
light_depth_texture: light_depth_texture.texture,
|
||||
light_depth_texture_view,
|
||||
point_light_depth_texture: point_light_depth_texture.texture,
|
||||
point_light_depth_texture_view,
|
||||
directional_light_depth_texture: directional_light_depth_texture.texture,
|
||||
directional_light_depth_texture_view,
|
||||
lights: view_lights,
|
||||
gpu_light_binding_index: light_meta.view_gpu_lights.push(gpu_lights),
|
||||
});
|
||||
|
@ -419,7 +600,7 @@ impl Node for ShadowPassNode {
|
|||
.get_manual(world, view_light_entity)
|
||||
.unwrap();
|
||||
let pass_descriptor = RenderPassDescriptor {
|
||||
label: Some("shadow_pass"),
|
||||
label: Some(&view_light.pass_name),
|
||||
color_attachments: &[],
|
||||
depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
|
||||
view: &view_light.depth_texture_view,
|
||||
|
|
|
@ -66,13 +66,13 @@ impl FromWorld for PbrShaders {
|
|||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
// TODO: change this to ViewUniform::std140_size_static once crevice fixes this!
|
||||
// TODO: change this to GpuLights::std140_size_static once crevice fixes this!
|
||||
// Context: https://github.com/LPGhatguy/crevice/issues/29
|
||||
min_binding_size: BufferSize::new(512),
|
||||
min_binding_size: BufferSize::new(1024),
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
// Shadow Texture Array
|
||||
// Point Shadow Texture Cube Array
|
||||
BindGroupLayoutEntry {
|
||||
binding: 2,
|
||||
visibility: ShaderStage::FRAGMENT,
|
||||
|
@ -83,7 +83,7 @@ impl FromWorld for PbrShaders {
|
|||
},
|
||||
count: None,
|
||||
},
|
||||
// Shadow Texture Array Sampler
|
||||
// Point Shadow Texture Array Sampler
|
||||
BindGroupLayoutEntry {
|
||||
binding: 3,
|
||||
visibility: ShaderStage::FRAGMENT,
|
||||
|
@ -93,6 +93,27 @@ impl FromWorld for PbrShaders {
|
|||
},
|
||||
count: None,
|
||||
},
|
||||
// Directional Shadow Texture Array
|
||||
BindGroupLayoutEntry {
|
||||
binding: 4,
|
||||
visibility: ShaderStage::FRAGMENT,
|
||||
ty: BindingType::Texture {
|
||||
multisampled: false,
|
||||
sample_type: TextureSampleType::Depth,
|
||||
view_dimension: TextureViewDimension::D2Array,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
// Directional Shadow Texture Array Sampler
|
||||
BindGroupLayoutEntry {
|
||||
binding: 5,
|
||||
visibility: ShaderStage::FRAGMENT,
|
||||
ty: BindingType::Sampler {
|
||||
comparison: true,
|
||||
filtering: true,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
label: None,
|
||||
});
|
||||
|
@ -379,7 +400,6 @@ pub fn extract_meshes(
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref image) = material.emissive_texture {
|
||||
if !images.contains(image) {
|
||||
continue;
|
||||
|
@ -537,11 +557,23 @@ pub fn queue_meshes(
|
|||
},
|
||||
BindGroupEntry {
|
||||
binding: 2,
|
||||
resource: BindingResource::TextureView(&view_lights.light_depth_texture_view),
|
||||
resource: BindingResource::TextureView(
|
||||
&view_lights.point_light_depth_texture_view,
|
||||
),
|
||||
},
|
||||
BindGroupEntry {
|
||||
binding: 3,
|
||||
resource: BindingResource::Sampler(&shadow_shaders.light_sampler),
|
||||
resource: BindingResource::Sampler(&shadow_shaders.point_light_sampler),
|
||||
},
|
||||
BindGroupEntry {
|
||||
binding: 4,
|
||||
resource: BindingResource::TextureView(
|
||||
&view_lights.directional_light_depth_texture_view,
|
||||
),
|
||||
},
|
||||
BindGroupEntry {
|
||||
binding: 5,
|
||||
resource: BindingResource::Sampler(&shadow_shaders.directional_light_sampler),
|
||||
},
|
||||
],
|
||||
label: None,
|
||||
|
|
|
@ -95,6 +95,16 @@ struct PointLight {
|
|||
radius: f32;
|
||||
near: f32;
|
||||
far: f32;
|
||||
shadow_bias_min: f32;
|
||||
shadow_bias_max: f32;
|
||||
};
|
||||
|
||||
struct DirectionalLight {
|
||||
view_projection: mat4x4<f32>;
|
||||
color: vec4<f32>;
|
||||
direction_to_light: vec3<f32>;
|
||||
shadow_bias_min: f32;
|
||||
shadow_bias_max: f32;
|
||||
};
|
||||
|
||||
[[block]]
|
||||
|
@ -102,8 +112,10 @@ struct Lights {
|
|||
// NOTE: this array size must be kept in sync with the constants defined bevy_pbr2/src/render/light.rs
|
||||
// TODO: this can be removed if we move to storage buffers for light arrays
|
||||
point_lights: array<PointLight, 10>;
|
||||
directional_lights: array<DirectionalLight, 1>;
|
||||
ambient_color: vec4<f32>;
|
||||
num_lights: u32;
|
||||
n_point_lights: u32;
|
||||
n_directional_lights: u32;
|
||||
};
|
||||
|
||||
let FLAGS_BASE_COLOR_TEXTURE_BIT: u32 = 1u;
|
||||
|
@ -117,9 +129,13 @@ let FLAGS_UNLIT_BIT: u32 = 32u;
|
|||
[[group(0), binding(1)]]
|
||||
var lights: Lights;
|
||||
[[group(0), binding(2)]]
|
||||
var shadow_textures: texture_depth_cube_array;
|
||||
var point_shadow_textures: texture_depth_cube_array;
|
||||
[[group(0), binding(3)]]
|
||||
var shadow_textures_sampler: sampler_comparison;
|
||||
var point_shadow_textures_sampler: sampler_comparison;
|
||||
[[group(0), binding(4)]]
|
||||
var directional_shadow_textures: texture_depth_2d_array;
|
||||
[[group(0), binding(5)]]
|
||||
var directional_shadow_textures_sampler: sampler_comparison;
|
||||
|
||||
[[group(2), binding(0)]]
|
||||
var material: StandardMaterial;
|
||||
|
@ -348,7 +364,22 @@ fn point_light(
|
|||
return ((diffuse + specular_light) * light.color.rgb) * (rangeAttenuation * NoL);
|
||||
}
|
||||
|
||||
fn fetch_shadow(light_id: i32, frag_position: vec4<f32>) -> f32 {
|
||||
fn directional_light(light: DirectionalLight, roughness: f32, NdotV: f32, normal: vec3<f32>, view: vec3<f32>, R: vec3<f32>, F0: vec3<f32>, diffuseColor: vec3<f32>) -> vec3<f32> {
|
||||
let incident_light = light.direction_to_light.xyz;
|
||||
|
||||
let half_vector = normalize(incident_light + view);
|
||||
let NoL = saturate(dot(normal, incident_light));
|
||||
let NoH = saturate(dot(normal, half_vector));
|
||||
let LoH = saturate(dot(incident_light, half_vector));
|
||||
|
||||
let diffuse = diffuseColor * Fd_Burley(roughness, NdotV, NoL, LoH);
|
||||
let specularIntensity = 1.0;
|
||||
let specular_light = specular(F0, roughness, half_vector, NdotV, NoL, NoH, LoH, specularIntensity);
|
||||
|
||||
return (specular_light + diffuse) * light.color.rgb * NoL;
|
||||
}
|
||||
|
||||
fn fetch_point_shadow(light_id: i32, frag_position: vec4<f32>, shadow_bias: f32) -> f32 {
|
||||
let light = lights.point_lights[light_id];
|
||||
|
||||
// because the shadow maps align with the axes and the frustum planes are at 45 degrees
|
||||
|
@ -382,7 +413,22 @@ fn fetch_shadow(light_id: i32, frag_position: vec4<f32>) -> f32 {
|
|||
// mip-mapping functionality. The shadow maps have no mipmaps so Level just samples
|
||||
// from LOD 0.
|
||||
let bias = 0.0001;
|
||||
return textureSampleCompareLevel(shadow_textures, shadow_textures_sampler, frag_ls, i32(light_id), depth - bias);
|
||||
return textureSampleCompareLevel(point_shadow_textures, point_shadow_textures_sampler, frag_ls, i32(light_id), depth - shadow_bias);
|
||||
}
|
||||
|
||||
fn fetch_directional_shadow(light_id: i32, homogeneous_coords: vec4<f32>, shadow_bias: f32) -> f32 {
|
||||
if (homogeneous_coords.w <= 0.0) {
|
||||
return 1.0;
|
||||
}
|
||||
// compensate for the Y-flip difference between the NDC and texture coordinates
|
||||
let flip_correction = vec2<f32>(0.5, -0.5);
|
||||
let proj_correction = 1.0 / homogeneous_coords.w;
|
||||
// compute texture coordinates for shadow lookup
|
||||
let light_local = homogeneous_coords.xy * flip_correction * proj_correction + vec2<f32>(0.5, 0.5);
|
||||
// do the lookup, using HW PCF and comparison
|
||||
// NOTE: Due to non-uniform control flow above, we must use the level variant of the texture
|
||||
// sampler to avoid use of implicit derivatives causing possible undefined behavior.
|
||||
return textureSampleCompareLevel(directional_shadow_textures, directional_shadow_textures_sampler, light_local, i32(light_id), homogeneous_coords.z * proj_correction - shadow_bias);
|
||||
}
|
||||
|
||||
struct FragmentInput {
|
||||
|
@ -471,10 +517,27 @@ fn fragment(in: FragmentInput) -> [[location(0)]] vec4<f32> {
|
|||
|
||||
// accumulate color
|
||||
var light_accum: vec3<f32> = vec3<f32>(0.0);
|
||||
for (var i: i32 = 0; i < i32(lights.num_lights); i = i + 1) {
|
||||
let n_point_lights = i32(lights.n_point_lights);
|
||||
let n_directional_lights = i32(lights.n_directional_lights);
|
||||
for (var i: i32 = 0; i < n_point_lights; i = i + 1) {
|
||||
let light = lights.point_lights[i];
|
||||
let light_contrib = point_light(in.world_position.xyz, light, roughness, NdotV, N, V, R, F0, diffuse_color);
|
||||
let shadow = fetch_shadow(i, in.world_position);
|
||||
let dir_to_light = normalize(light.position.xyz - in.world_position.xyz);
|
||||
let shadow_bias = max(
|
||||
light.shadow_bias_max * (1.0 - dot(in.world_normal, dir_to_light)),
|
||||
light.shadow_bias_min
|
||||
);
|
||||
let shadow = fetch_point_shadow(i, in.world_position, shadow_bias);
|
||||
light_accum = light_accum + light_contrib * shadow;
|
||||
}
|
||||
for (var i: i32 = 0; i < n_directional_lights; i = i + 1) {
|
||||
let light = lights.directional_lights[i];
|
||||
let light_contrib = directional_light(light, roughness, NdotV, N, V, R, F0, diffuse_color);
|
||||
let shadow_bias = max(
|
||||
light.shadow_bias_max * (1.0 - dot(in.world_normal, light.direction_to_light.xyz)),
|
||||
light.shadow_bias_min
|
||||
);
|
||||
let shadow = fetch_directional_shadow(i, light.view_projection * in.world_position, shadow_bias);
|
||||
light_accum = light_accum + light_contrib * shadow;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue