Work in progress towards 2D lighting
This commit is contained in:
@@ -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
88
src/canvas/tile_light.rs
Normal 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.
|
||||
}
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user