Work in progress towards 2D lighting

This commit is contained in:
2023-01-26 21:24:50 +01:00
parent 0124123189
commit 112c7bc94d
7 changed files with 254 additions and 29 deletions

58
Cargo.lock generated
View File

@@ -43,9 +43,9 @@ dependencies = [
[[package]]
name = "ahash"
version = "0.8.2"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107"
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
dependencies = [
"cfg-if",
"getrandom",
@@ -1494,7 +1494,7 @@ version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc9fcd393c3daaaf5909008a1d948319d538b79c51871e4df0993260260a94e4"
dependencies = [
"ahash 0.8.2",
"ahash 0.8.3",
"epaint",
"nohash-hasher",
]
@@ -1563,7 +1563,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ba04741be7f6602b1a1b28f1082cce45948a7032961c52814f8946b28493300"
dependencies = [
"ab_glyph",
"ahash 0.8.2",
"ahash 0.8.3",
"atomic_refcell",
"bytemuck",
"emath",
@@ -2524,6 +2524,15 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "nom8"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8"
dependencies = [
"memchr",
]
[[package]]
name = "notify"
version = "5.0.0"
@@ -2617,18 +2626,18 @@ dependencies = [
[[package]]
name = "num_enum"
version = "0.5.7"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9"
checksum = "8d829733185c1ca374f17e52b762f24f535ec625d2cc1f070e34c8a9068f341b"
dependencies = [
"num_enum_derive",
]
[[package]]
name = "num_enum_derive"
version = "0.5.7"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
checksum = "2be1598bf1c313dcdd12092e3f1920f463462525a21b7b4e11b4168353d0123e"
dependencies = [
"proc-macro-crate",
"proc-macro2",
@@ -2842,19 +2851,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "pretty-type-name"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8815d101cfb4cb491154896bdab292a395a7ac9ab185a9941a2f5be0135900d"
checksum = "f0f73cdaf19b52e6143685c3606206e114a4dfa969d6b14ec3894c88eb38bd4b"
[[package]]
name = "proc-macro-crate"
version = "1.2.1"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9"
checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34"
dependencies = [
"once_cell",
"thiserror",
"toml",
"toml_edit",
]
[[package]]
@@ -3370,6 +3378,23 @@ dependencies = [
"serde",
]
[[package]]
name = "toml_datetime"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5"
[[package]]
name = "toml_edit"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "729bfd096e40da9c001f778f5cdecbd2957929a24e10e5883d9392220a751581"
dependencies = [
"indexmap",
"nom8",
"toml_datetime",
]
[[package]]
name = "tracing"
version = "0.1.37"
@@ -3700,9 +3725,9 @@ dependencies = [
[[package]]
name = "webbrowser"
version = "0.8.4"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e74f5ff7786c4c21f61ba8e30ea29c9745f06fca0a4a02d083b3c662583399e8"
checksum = "769f1a8831de12cad7bd6f9693b15b1432d93a151557810f617f626af823acae"
dependencies = [
"core-foundation",
"dirs",
@@ -3713,7 +3738,6 @@ dependencies = [
"raw-window-handle 0.5.0",
"url",
"web-sys",
"windows 0.43.0",
]
[[package]]

View File

@@ -1,12 +1,37 @@
struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
struct FragmentInput {
@builtin(position) fragment_coordinate: vec4<f32>,
@location(0) world_position: vec4<f32>,
@location(1) world_normal: vec3<f32>,
@location(2) uv: vec2<f32>,
};
struct TileLight {
color: vec4<f32>,
intensity: f32,
position: vec2<f32>,
};
struct CanvasMaterial {
ambient_color: vec4<f32>,
tile_lights: array<TileLight, 256u>,
number_of_lights: u32,
};
@group(1) @binding(0)
var<uniform> canvas_material: CanvasMaterial;
@fragment
fn fragment(input: VertexOutput) -> @location(0) vec4<f32> {
var output_color = vec4<f32>(input.uv, 1.0, 1.0);
fn fragment(input: FragmentInput) -> @location(0) vec4<f32> {
var output_color = canvas_material.ambient_color;
var lighting = vec4<f32>();
for (var i: u32 = 0u; i < canvas_material.number_of_lights; i++) {
var luminance = canvas_material.tile_lights[i].intensity * pow(length(canvas_material.tile_lights[i].position - input.world_position.xy), -1.7) * 2.0;
lighting += vec4<f32>(luminance * canvas_material.tile_lights[i].color.rgb, 0.0);
}
output_color += lighting;
return output_color;
}

View File

@@ -1,10 +1,20 @@
mod tile_light;
use crate::grid;
use bevy::{
prelude::*,
reflect::TypeUuid,
render::render_resource::{AsBindGroup, ShaderRef},
sprite::{Material2d, Material2dPlugin, MaterialMesh2dBundle},
render::{
render_resource::{encase, AsBindGroup, OwnedBindingResource, ShaderRef, ShaderType},
renderer::RenderQueue,
RenderApp, RenderStage,
},
sprite::{Material2d, Material2dPlugin, MaterialMesh2dBundle, RenderMaterials2d},
};
use tile_light::{
extract_tile_lights, prepare_tile_lights, TileLight, TileLights, TileLightsUniform,
};
pub(crate) use tile_light::EmissiveTile;
pub struct CanvasPlugin;
@@ -12,17 +22,92 @@ impl Plugin for CanvasPlugin {
fn build(&self, app: &mut App) {
app.add_plugin(Material2dPlugin::<CanvasMaterial>::default())
.add_startup_system(spawn_canvas);
app.sub_app_mut(RenderApp)
.init_resource::<TileLights>()
.add_system_to_stage(RenderStage::Extract, extract_tile_lights)
.add_system_to_stage(RenderStage::Prepare, prepare_canvas_material);
// .add_system_to_stage(RenderStage::Prepare, prepare_tile_lights);
}
}
#[derive(AsBindGroup, TypeUuid, Clone)]
#[uuid = "24f83f6e-e52d-41a6-bf1d-0e46e57a4995"]
struct CanvasMaterial {}
struct CanvasMaterial {
#[uniform(0)]
ambient_color: Color,
#[uniform(0)]
tile_lights: tile_light::TileLightsUniform,
#[uniform(0)]
number_of_lights: u32,
}
impl Default for CanvasMaterial {
fn default() -> Self {
Self {
ambient_color: Color::rgb(0.1, 0.1, 0.1),
number_of_lights: 0,
tile_lights: Default::default(),
}
}
}
#[derive(ShaderType)]
struct CanvasMaterialUniform {
ambient_color: Color,
tile_lights: tile_light::TileLightsUniform,
number_of_lights: u32,
}
impl Material2d for CanvasMaterial {
fn fragment_shader() -> ShaderRef {
"canvas_shader.wgsl".into()
}
// fn specialize(
// descriptor: &mut bevy::render::render_resource::RenderPipelineDescriptor,
// layout: &bevy::render::mesh::MeshVertexBufferLayout,
// key: bevy::sprite::Material2dKey<Self>,
// ) -> Result<(), bevy::render::render_resource::SpecializedMeshPipelineError> {
// if let Some(layouts) = descriptor.layout {
// layouts.push(BindGr);
// }
// Ok(())
// }
}
fn prepare_canvas_material(
materials: Res<RenderMaterials2d<CanvasMaterial>>,
canvas_query: Query<&Handle<CanvasMaterial>>,
tile_light_query: Query<&TileLight>,
render_queue: Res<RenderQueue>,
) {
let tile_lights = tile_light_query.iter().cloned().collect::<Vec<_>>();
let mut tile_lights_uniform = tile_light::TileLightsUniform::default();
// tile_lights_uniform.data.copy_from_slice(&tile_lights);
let len = tile_lights.len().min(256);
let src = &tile_lights[..len];
let dst = &mut tile_lights_uniform.data[..len];
dst.copy_from_slice(src);
for handle in canvas_query.iter() {
if let Some(material) = materials.get(handle) {
let binding = &material.bindings[0];
if let OwnedBindingResource::Buffer(cur_buffer) = binding {
let mut buffer = encase::UniformBuffer::new(Vec::new());
buffer
.write(&CanvasMaterialUniform {
ambient_color: Color::rgb_u8(12, 12, 12),
tile_lights: tile_lights_uniform.clone(),
number_of_lights: tile_lights.len() as _,
})
.unwrap();
render_queue.write_buffer(cur_buffer, 0, buffer.as_ref());
}
}
}
}
fn spawn_canvas(
@@ -33,7 +118,7 @@ fn spawn_canvas(
commands
.spawn(MaterialMesh2dBundle {
mesh: mesh_assets.add(Mesh::from(shape::Quad::default())).into(),
material: canvas_material_assets.add(CanvasMaterial {}),
material: canvas_material_assets.add(CanvasMaterial::default()),
transform: Transform::from_scale(Vec3::splat(
grid::SEGMENT_SIZE * f32::from(grid::SIZE),
)),

88
src/canvas/tile_light.rs Normal file
View File

@@ -0,0 +1,88 @@
use bevy::{
math::Vec3Swizzles,
prelude::*,
render::{
render_resource::{ShaderType, UniformBuffer},
renderer::{RenderDevice, RenderQueue},
Extract,
},
sprite::Material2dPipeline,
};
use super::CanvasMaterial;
const MAX_TILE_LIGHTS: usize = 256;
#[derive(Component, Clone, Copy)]
pub(crate) struct EmissiveTile {
pub intensity: f32,
}
impl Default for EmissiveTile {
fn default() -> Self {
Self { intensity: 1.0 }
}
}
#[derive(Copy, Clone, Default, ShaderType, Component)]
pub(super) struct TileLight {
color: Color,
intensity: f32,
position: Vec2,
}
#[derive(Default, Resource)]
pub(super) struct TileLights(UniformBuffer<TileLightsUniform>);
#[derive(ShaderType, Clone)]
pub(super) struct TileLightsUniform {
pub data: Box<[TileLight; MAX_TILE_LIGHTS]>,
}
impl Default for TileLightsUniform {
fn default() -> Self {
Self {
data: Box::new([TileLight::default(); MAX_TILE_LIGHTS]),
}
}
}
impl TileLights {
fn set(&mut self, lights: &[TileLight]) {
let len = lights.len().min(MAX_TILE_LIGHTS);
let src = &lights[..len];
let dst = &mut self.0.get_mut().data[..len];
dst.copy_from_slice(src);
}
fn write_buffer(&mut self, render_device: &RenderDevice, render_queue: &RenderQueue) {
self.0.write_buffer(render_device, render_queue);
}
}
pub(super) fn extract_tile_lights(
mut commands: Commands,
emissive_sprite_query: Extract<Query<(Entity, &EmissiveTile, &Sprite, &GlobalTransform)>>,
) {
for (entity, emissive_sprite, sprite, global_transform) in emissive_sprite_query.iter() {
commands.get_or_spawn(entity).insert(TileLight {
color: sprite.color,
intensity: emissive_sprite.intensity,
position: global_transform.translation().xy(),
});
}
}
pub(super) fn prepare_tile_lights(
render_device: Res<RenderDevice>,
render_queue: Res<RenderQueue>,
canvas_material_pipeline: Res<Material2dPipeline<CanvasMaterial>>,
light_query: Query<&TileLight>,
mut tile_lights: ResMut<TileLights>,
) {
let lights = light_query.iter().cloned().collect::<Vec<_>>();
tile_lights.set(&lights);
tile_lights.write_buffer(&render_device, &render_queue);
// canvas_material_pipeline.
}

View File

@@ -63,6 +63,7 @@ fn spawn_fruit_system(mut commands: Commands, coordinate_query: Query<&grid::Coo
})
.insert(fruit_coordinate)
.insert(Fruit)
.insert(crate::canvas::EmissiveTile { intensity: 1.0 })
.insert(Name::new("Fruit"));
}

View File

@@ -75,10 +75,11 @@ fn setup_system(mut commands: Commands) {
..Default::default()
})
.insert(Name::new("Orthographic Camera"))
.insert(BloomSettings {
threshold: 0.7,
..Default::default()
});
// .insert(BloomSettings {
// threshold: 0.7,
// ..Default::default()
// })
;
}
fn camera_move_system(

View File

@@ -129,6 +129,7 @@ fn create_snake_segment(commands: &mut Commands, grid_position: grid::Coordinate
})
.insert(SnakeSegment)
.insert(grid_position)
.insert(crate::canvas::EmissiveTile { intensity: 1.0 })
.id()
}