use bevy::{ pbr::NotShadowCaster, prelude::*, render::render_resource::{AsBindGroup, ShaderRef}, }; use crate::camera_controller::{CameraController, CameraMotionSystem}; pub struct WorldGridPlugin; impl Plugin for WorldGridPlugin { fn build(&self, app: &mut App) { app.add_plugins(MaterialPlugin::::default()) .add_systems(Startup, spawn_world_grid) .add_systems(PostUpdate, move_plane_with_camera.after(CameraMotionSystem)); } } #[derive(Component)] pub struct WorldGridPlane; #[derive(Asset, AsBindGroup, TypePath, Clone)] struct ProceduralGridMaterial {} impl Material for ProceduralGridMaterial { fn fragment_shader() -> ShaderRef { "shaders/procedural_grid.wgsl".into() } fn alpha_mode(&self) -> AlphaMode { AlphaMode::Blend } } fn spawn_world_grid( mut cmd: Commands, mut ra_meshes: ResMut>, mut ra_mat_proc_grid: ResMut>, ) { let plane = ra_meshes.add(Mesh::from(shape::Plane { size: 200.0, subdivisions: 0, })); let proc_grid = ra_mat_proc_grid.add(ProceduralGridMaterial {}); cmd.spawn(( Name::new("World Grid"), SpatialBundle::from_transform(Transform::IDENTITY), WorldGridPlane, )) .with_children(|parent| { parent.spawn(( MaterialMeshBundle { mesh: plane.clone(), material: proc_grid.clone(), transform: Transform::IDENTITY, ..default() }, NotShadowCaster, )); parent.spawn(( MaterialMeshBundle { mesh: plane, material: proc_grid, transform: Transform::IDENTITY.looking_to(Vec3::Z, Vec3::NEG_Y), ..default() }, NotShadowCaster, )); }); } fn move_plane_with_camera( mut plane: Query<(&WorldGridPlane, &mut Transform)>, camera: Query<&CameraController, Changed>, ) { if let Ok(&CameraController { focus, .. }) = camera.get_single() { let (_, mut xform) = plane.single_mut(); xform.translation.x = focus.x; xform.translation.z = focus.z; } }