Added polar shadowmaps for lights
parent
4cec5f45fe
commit
9056e8350b
|
|
@ -35,6 +35,12 @@ var<uniform> spot_light_count: i32;
|
|||
@group(1) @binding(4)
|
||||
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
|
||||
fn fragment(
|
||||
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 diff = pos - point_lights[i].position;
|
||||
let dist = distance(pos, point_lights[i].position);
|
||||
let edge_treshold = radius * light_edge_mult - light_edge;
|
||||
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;
|
||||
dim_light = dim_light + step(dist, radius);
|
||||
dim_light = dim_light + 1.0 / max(dist - radius, 0.0);
|
||||
|
||||
let uv = vec2<f32>(
|
||||
(atan2(diff.y, diff.x) + radians(180.0)) / radians(360.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++) {
|
||||
|
|
@ -74,11 +86,17 @@ fn fragment(
|
|||
let spot_dir = vec2<f32>(cos(spot.rotation), sin(spot.rotation));
|
||||
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_dist = max(dist - edge_treshold, 0.0);
|
||||
let angle_mult = step(angle_diff, spot.angle / 2.0);
|
||||
bright_light = bright_light + step(dist, edge_treshold) * angle_mult;
|
||||
dim_light = dim_light + step(dist, radius) * 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 * step(dist, max_range);
|
||||
}
|
||||
|
||||
let edge1 = step(bright_light, 0.75);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::{debug, game_setup};
|
|||
use bevy::prelude::*;
|
||||
use bevy_ecs_ldtk::{LdtkWorldBundle, LevelSelection};
|
||||
|
||||
use self::darkness::{PointLight2D, SpotLight2D};
|
||||
use self::darkness::SpotLight2D;
|
||||
|
||||
pub mod camera;
|
||||
pub mod darkness;
|
||||
|
|
@ -36,6 +36,5 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>) {
|
|||
radius: 100.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),
|
||||
),
|
||||
},
|
||||
transform: Transform::from_xyz(0.0, 0.0, 999.9),
|
||||
transform: Transform::from_xyz(128.0, -73.0, 999.9),
|
||||
..default()
|
||||
},
|
||||
GameCamera::default(),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
use bevy::{
|
||||
core::bytes_of,
|
||||
prelude::*,
|
||||
render::{mesh::Indices, render_resource::ShaderType},
|
||||
render::{
|
||||
mesh::Indices,
|
||||
render_resource::{Extent3d, ShaderType, TextureDimension},
|
||||
},
|
||||
sprite::{Material2dPlugin, Mesh2dHandle},
|
||||
};
|
||||
use bevy_ecs_ldtk::{LdtkLevel, LevelEvent};
|
||||
|
|
@ -12,6 +16,7 @@ pub use material::*;
|
|||
// Needs to be the same as in darkness.wgsl
|
||||
pub const MAX_POINT_LIGHTS: usize = 64;
|
||||
pub const MAX_SPOT_LIGHTS: usize = 64;
|
||||
pub const SHADOWMAP_RESOLUTION: usize = 256;
|
||||
|
||||
pub struct DarknessPlugin;
|
||||
|
||||
|
|
@ -82,6 +87,7 @@ fn add_to_level(
|
|||
mut level_events: EventReader<LevelEvent>,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<DarknessMaterial>>,
|
||||
mut images: ResMut<Assets<Image>>,
|
||||
level_query: Query<(Entity, &Handle<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_UV_0, uvs);
|
||||
|
||||
let width = SHADOWMAP_RESOLUTION;
|
||||
let height = MAX_SPOT_LIGHTS + MAX_POINT_LIGHTS;
|
||||
|
||||
commands.entity(entity).with_children(|builder| {
|
||||
builder.spawn((
|
||||
Name::new("Darkness plane"),
|
||||
DarknessMeshBundle {
|
||||
transform: Transform::from_xyz(0.0, 0.0, 100.0),
|
||||
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()
|
||||
},
|
||||
));
|
||||
|
|
@ -151,6 +172,7 @@ fn add_to_level(
|
|||
|
||||
fn prepare_lights(
|
||||
mut materials: ResMut<Assets<DarknessMaterial>>,
|
||||
mut images: ResMut<Assets<Image>>,
|
||||
material_query: Query<&Handle<DarknessMaterial>>,
|
||||
point_light_query: Query<(&GlobalTransform, &PointLight2D)>,
|
||||
spot_light_query: Query<(&GlobalTransform, &SpotLight2D)>,
|
||||
|
|
@ -163,6 +185,14 @@ fn prepare_lights(
|
|||
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;
|
||||
point_lights
|
||||
.iter()
|
||||
|
|
@ -171,6 +201,15 @@ fn prepare_lights(
|
|||
material.point_lights[i] = GpuPointLight2D {
|
||||
position: transform.translation().truncate(),
|
||||
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,
|
||||
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,
|
||||
#[uniform(4)]
|
||||
pub(crate) spot_lights: [GpuSpotLight2D; MAX_SPOT_LIGHTS],
|
||||
#[texture(5)]
|
||||
#[sampler(6)]
|
||||
pub shadowmap_texture: Option<Handle<Image>>,
|
||||
}
|
||||
|
||||
impl Default for DarknessMaterial {
|
||||
|
|
@ -38,13 +41,18 @@ impl Default for DarknessMaterial {
|
|||
point_lights: [GpuPointLight2D::default(); MAX_POINT_LIGHTS],
|
||||
spot_light_count: 0,
|
||||
spot_lights: [GpuSpotLight2D::default(); MAX_SPOT_LIGHTS],
|
||||
shadowmap_texture: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DarknessMaterial {
|
||||
pub fn new(color: Color) -> Self {
|
||||
Self { color, ..default() }
|
||||
pub fn new(color: Color, shadowmap_texture: Option<Handle<Image>>) -> Self {
|
||||
Self {
|
||||
color,
|
||||
shadowmap_texture,
|
||||
..default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue