Added polar shadowmaps for lights
parent
4cec5f45fe
commit
9056e8350b
|
|
@ -35,6 +35,12 @@ var<uniform> spot_light_count: i32;
|
||||||
@group(1) @binding(4)
|
@group(1) @binding(4)
|
||||||
var<uniform> spot_lights: array<SpotLight, 64>;
|
var<uniform> spot_lights: array<SpotLight, 64>;
|
||||||
|
|
||||||
|
@group(1) @binding(5)
|
||||||
|
var shadowmap_texture: texture_2d<f32>;
|
||||||
|
|
||||||
|
@group(1) @binding(6)
|
||||||
|
var shadowmap_sampler: sampler;
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fragment(
|
fn fragment(
|
||||||
mesh: MeshVertexOutput,
|
mesh: MeshVertexOutput,
|
||||||
|
|
@ -54,13 +60,19 @@ fn fragment(
|
||||||
}
|
}
|
||||||
let radius = point_lights[i].radius - (sin(t * 5.0) * 0.5 + 0.5) * 0.2;
|
let radius = point_lights[i].radius - (sin(t * 5.0) * 0.5 + 0.5) * 0.2;
|
||||||
|
|
||||||
|
let diff = pos - point_lights[i].position;
|
||||||
let dist = distance(pos, point_lights[i].position);
|
let dist = distance(pos, point_lights[i].position);
|
||||||
let edge_treshold = radius * light_edge_mult - light_edge;
|
let edge_treshold = radius * light_edge_mult - light_edge;
|
||||||
let edge_dist = max(dist - edge_treshold, 0.0);
|
let edge_dist = max(dist - edge_treshold, 0.0);
|
||||||
bright_light = bright_light + step(dist, edge_treshold);
|
|
||||||
bright_light = bright_light + 1.0 / edge_dist;
|
let uv = vec2<f32>(
|
||||||
dim_light = dim_light + step(dist, radius);
|
(atan2(diff.y, diff.x) + radians(180.0)) / radians(360.0),
|
||||||
dim_light = dim_light + 1.0 / max(dist - radius, 0.0);
|
f32(i) / 128.0
|
||||||
|
);
|
||||||
|
let max_range = textureSample(shadowmap_texture, shadowmap_sampler, uv).r;
|
||||||
|
|
||||||
|
bright_light = bright_light + step(dist, edge_treshold) * step(dist, max_range);
|
||||||
|
dim_light = dim_light + step(dist, radius) * step(dist, max_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i: i32 = 0; i < spot_light_count; i++) {
|
for (var i: i32 = 0; i < spot_light_count; i++) {
|
||||||
|
|
@ -74,11 +86,17 @@ fn fragment(
|
||||||
let spot_dir = vec2<f32>(cos(spot.rotation), sin(spot.rotation));
|
let spot_dir = vec2<f32>(cos(spot.rotation), sin(spot.rotation));
|
||||||
let angle_diff = acos(dot(spot_dir, normalize(diff)));
|
let angle_diff = acos(dot(spot_dir, normalize(diff)));
|
||||||
|
|
||||||
|
let uv = vec2<f32>(
|
||||||
|
(atan2(diff.y, diff.x) + radians(180.0)) / radians(360.0),
|
||||||
|
f32(i + 64) / 128.0
|
||||||
|
);
|
||||||
|
let max_range = textureSample(shadowmap_texture, shadowmap_sampler, uv).r;
|
||||||
|
|
||||||
let edge_treshold = radius * light_edge_mult - light_edge;
|
let edge_treshold = radius * light_edge_mult - light_edge;
|
||||||
let edge_dist = max(dist - edge_treshold, 0.0);
|
let edge_dist = max(dist - edge_treshold, 0.0);
|
||||||
let angle_mult = step(angle_diff, spot.angle / 2.0);
|
let angle_mult = step(angle_diff, spot.angle / 2.0);
|
||||||
bright_light = bright_light + step(dist, edge_treshold) * angle_mult;
|
bright_light = bright_light + step(dist, edge_treshold) * angle_mult * step(dist, max_range);
|
||||||
dim_light = dim_light + step(dist, radius) * angle_mult;
|
dim_light = dim_light + step(dist, radius) * angle_mult * step(dist, max_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
let edge1 = step(bright_light, 0.75);
|
let edge1 = step(bright_light, 0.75);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use crate::{debug, game_setup};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_ecs_ldtk::{LdtkWorldBundle, LevelSelection};
|
use bevy_ecs_ldtk::{LdtkWorldBundle, LevelSelection};
|
||||||
|
|
||||||
use self::darkness::{PointLight2D, SpotLight2D};
|
use self::darkness::SpotLight2D;
|
||||||
|
|
||||||
pub mod camera;
|
pub mod camera;
|
||||||
pub mod darkness;
|
pub mod darkness;
|
||||||
|
|
@ -36,6 +36,5 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>) {
|
||||||
radius: 100.0,
|
radius: 100.0,
|
||||||
angle: 1.0,
|
angle: 1.0,
|
||||||
},
|
},
|
||||||
PointLight2D { radius: 20.0 },
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ fn camera_setup(mut commands: Commands) {
|
||||||
Color::rgb(0.0, 0.0, 0.0),
|
Color::rgb(0.0, 0.0, 0.0),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
transform: Transform::from_xyz(0.0, 0.0, 999.9),
|
transform: Transform::from_xyz(128.0, -73.0, 999.9),
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
GameCamera::default(),
|
GameCamera::default(),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
use bevy::{
|
use bevy::{
|
||||||
|
core::bytes_of,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
render::{mesh::Indices, render_resource::ShaderType},
|
render::{
|
||||||
|
mesh::Indices,
|
||||||
|
render_resource::{Extent3d, ShaderType, TextureDimension},
|
||||||
|
},
|
||||||
sprite::{Material2dPlugin, Mesh2dHandle},
|
sprite::{Material2dPlugin, Mesh2dHandle},
|
||||||
};
|
};
|
||||||
use bevy_ecs_ldtk::{LdtkLevel, LevelEvent};
|
use bevy_ecs_ldtk::{LdtkLevel, LevelEvent};
|
||||||
|
|
@ -12,6 +16,7 @@ pub use material::*;
|
||||||
// Needs to be the same as in darkness.wgsl
|
// Needs to be the same as in darkness.wgsl
|
||||||
pub const MAX_POINT_LIGHTS: usize = 64;
|
pub const MAX_POINT_LIGHTS: usize = 64;
|
||||||
pub const MAX_SPOT_LIGHTS: usize = 64;
|
pub const MAX_SPOT_LIGHTS: usize = 64;
|
||||||
|
pub const SHADOWMAP_RESOLUTION: usize = 256;
|
||||||
|
|
||||||
pub struct DarknessPlugin;
|
pub struct DarknessPlugin;
|
||||||
|
|
||||||
|
|
@ -82,6 +87,7 @@ fn add_to_level(
|
||||||
mut level_events: EventReader<LevelEvent>,
|
mut level_events: EventReader<LevelEvent>,
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
mut materials: ResMut<Assets<DarknessMaterial>>,
|
mut materials: ResMut<Assets<DarknessMaterial>>,
|
||||||
|
mut images: ResMut<Assets<Image>>,
|
||||||
level_query: Query<(Entity, &Handle<LdtkLevel>)>,
|
level_query: Query<(Entity, &Handle<LdtkLevel>)>,
|
||||||
levels: Res<Assets<LdtkLevel>>,
|
levels: Res<Assets<LdtkLevel>>,
|
||||||
) {
|
) {
|
||||||
|
|
@ -131,13 +137,28 @@ fn add_to_level(
|
||||||
plane.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
|
plane.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
|
||||||
plane.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs);
|
plane.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs);
|
||||||
|
|
||||||
|
let width = SHADOWMAP_RESOLUTION;
|
||||||
|
let height = MAX_SPOT_LIGHTS + MAX_POINT_LIGHTS;
|
||||||
|
|
||||||
commands.entity(entity).with_children(|builder| {
|
commands.entity(entity).with_children(|builder| {
|
||||||
builder.spawn((
|
builder.spawn((
|
||||||
Name::new("Darkness plane"),
|
Name::new("Darkness plane"),
|
||||||
DarknessMeshBundle {
|
DarknessMeshBundle {
|
||||||
transform: Transform::from_xyz(0.0, 0.0, 100.0),
|
transform: Transform::from_xyz(0.0, 0.0, 100.0),
|
||||||
mesh: Mesh2dHandle(meshes.add(plane)),
|
mesh: Mesh2dHandle(meshes.add(plane)),
|
||||||
material: materials.add(DarknessMaterial::default()),
|
material: materials.add(DarknessMaterial::new(
|
||||||
|
Color::rgba(0.0, 0.0, 0.0, 0.75),
|
||||||
|
Some(images.add(Image::new(
|
||||||
|
Extent3d {
|
||||||
|
width: width as u32,
|
||||||
|
height: height as u32,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
TextureDimension::D2,
|
||||||
|
vec![0; width * height * 4],
|
||||||
|
bevy::render::render_resource::TextureFormat::R32Float,
|
||||||
|
))),
|
||||||
|
)),
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|
@ -151,6 +172,7 @@ fn add_to_level(
|
||||||
|
|
||||||
fn prepare_lights(
|
fn prepare_lights(
|
||||||
mut materials: ResMut<Assets<DarknessMaterial>>,
|
mut materials: ResMut<Assets<DarknessMaterial>>,
|
||||||
|
mut images: ResMut<Assets<Image>>,
|
||||||
material_query: Query<&Handle<DarknessMaterial>>,
|
material_query: Query<&Handle<DarknessMaterial>>,
|
||||||
point_light_query: Query<(&GlobalTransform, &PointLight2D)>,
|
point_light_query: Query<(&GlobalTransform, &PointLight2D)>,
|
||||||
spot_light_query: Query<(&GlobalTransform, &SpotLight2D)>,
|
spot_light_query: Query<(&GlobalTransform, &SpotLight2D)>,
|
||||||
|
|
@ -163,6 +185,14 @@ fn prepare_lights(
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let shadowmap = match &material.shadowmap_texture {
|
||||||
|
Some(handle) => match images.get_mut(&handle) {
|
||||||
|
Some(image) => image,
|
||||||
|
None => continue,
|
||||||
|
},
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
|
||||||
material.point_light_count = point_lights.len() as i32;
|
material.point_light_count = point_lights.len() as i32;
|
||||||
point_lights
|
point_lights
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -171,6 +201,15 @@ fn prepare_lights(
|
||||||
material.point_lights[i] = GpuPointLight2D {
|
material.point_lights[i] = GpuPointLight2D {
|
||||||
position: transform.translation().truncate(),
|
position: transform.translation().truncate(),
|
||||||
radius: light.radius,
|
radius: light.radius,
|
||||||
|
};
|
||||||
|
for x in 0..SHADOWMAP_RESOLUTION {
|
||||||
|
let offset = (i * SHADOWMAP_RESOLUTION + x) * 4;
|
||||||
|
let distance = x as f32 / SHADOWMAP_RESOLUTION as f32 * light.radius;
|
||||||
|
let distance_bytes = bytes_of(&distance);
|
||||||
|
shadowmap.data[offset + 0] = distance_bytes[0];
|
||||||
|
shadowmap.data[offset + 1] = distance_bytes[1];
|
||||||
|
shadowmap.data[offset + 2] = distance_bytes[2];
|
||||||
|
shadowmap.data[offset + 3] = distance_bytes[3];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -188,6 +227,15 @@ fn prepare_lights(
|
||||||
padding2: 0,
|
padding2: 0,
|
||||||
padding3: 0,
|
padding3: 0,
|
||||||
};
|
};
|
||||||
|
for x in 0..SHADOWMAP_RESOLUTION {
|
||||||
|
let offset = ((i + MAX_POINT_LIGHTS) * SHADOWMAP_RESOLUTION + x) * 4;
|
||||||
|
let distance = x as f32 / SHADOWMAP_RESOLUTION as f32 * light.radius;
|
||||||
|
let distance_bytes = bytes_of(&distance);
|
||||||
|
shadowmap.data[offset + 0] = distance_bytes[0];
|
||||||
|
shadowmap.data[offset + 1] = distance_bytes[1];
|
||||||
|
shadowmap.data[offset + 2] = distance_bytes[2];
|
||||||
|
shadowmap.data[offset + 3] = distance_bytes[3];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,9 @@ pub struct DarknessMaterial {
|
||||||
pub(crate) spot_light_count: i32,
|
pub(crate) spot_light_count: i32,
|
||||||
#[uniform(4)]
|
#[uniform(4)]
|
||||||
pub(crate) spot_lights: [GpuSpotLight2D; MAX_SPOT_LIGHTS],
|
pub(crate) spot_lights: [GpuSpotLight2D; MAX_SPOT_LIGHTS],
|
||||||
|
#[texture(5)]
|
||||||
|
#[sampler(6)]
|
||||||
|
pub shadowmap_texture: Option<Handle<Image>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for DarknessMaterial {
|
impl Default for DarknessMaterial {
|
||||||
|
|
@ -38,13 +41,18 @@ impl Default for DarknessMaterial {
|
||||||
point_lights: [GpuPointLight2D::default(); MAX_POINT_LIGHTS],
|
point_lights: [GpuPointLight2D::default(); MAX_POINT_LIGHTS],
|
||||||
spot_light_count: 0,
|
spot_light_count: 0,
|
||||||
spot_lights: [GpuSpotLight2D::default(); MAX_SPOT_LIGHTS],
|
spot_lights: [GpuSpotLight2D::default(); MAX_SPOT_LIGHTS],
|
||||||
|
shadowmap_texture: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DarknessMaterial {
|
impl DarknessMaterial {
|
||||||
pub fn new(color: Color) -> Self {
|
pub fn new(color: Color, shadowmap_texture: Option<Handle<Image>>) -> Self {
|
||||||
Self { color, ..default() }
|
Self {
|
||||||
|
color,
|
||||||
|
shadowmap_texture,
|
||||||
|
..default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue