use bevy::{ core_pipeline::core_3d::Opaque3d, ecs::{ query::WorldQuery, system::{lifetimeless::Read, SystemParam, SystemState}, }, pbr::SetMeshViewBindGroup, prelude::*, reflect::TypeUuid, render::{ extract_resource::ExtractResource, render_phase::{ AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult, RenderPhase, SetItemPipeline, TrackedRenderPass, }, render_resource::{ BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, Buffer, BufferBinding, BufferBindingType, BufferInitDescriptor, BufferUsages, ColorTargetState, ColorWrites, CompareFunction, DepthStencilState, FragmentState, FrontFace, MultisampleState, PipelineCache, PolygonMode, PrimitiveState, PrimitiveTopology, RenderPipelineDescriptor, ShaderStages, ShaderType, SpecializedRenderPipeline, SpecializedRenderPipelines, TextureFormat, UniformBuffer, VertexState, BlendState, }, renderer::{RenderDevice, RenderQueue}, texture::DefaultImageSampler, view::{ViewTarget, ViewUniformOffset, ViewUniforms}, Extract, RenderApp, RenderSet, }, }; use std::num::NonZeroU64; mod astro; /// Conversion between game units and astronomical ones. #[derive(Clone, Resource)] pub struct GameUnitsToCelestial { /// The geodetic latitude in degress of the point on the Earth's surface corresponding to the /// world space origin. pub origin_latitude: f32, /// The longitude in degress of the point on the Earth's surface corresponding to the world /// space origin. pub origin_longitude: f32, /// The heading of the world space coordinate frame in degrees. A value of 0.0 means that the /// -Z axis points north. A value of 45.0 means that the -Z axis points northeast. pub heading: f32, /// The [Julian date](https://en.wikipedia.org/wiki/Julian_date) of the start of the game. /// /// Defaults to 2451544.5 which corresponds to midnight UTC on January 1st, 2000. pub initial_julian_date: f64, /// Scale factor between the game's time and the real world's time. /// /// Defaults to 1.0. Set to 0.0 to have stars stop moving, or to large values to have stars /// move quickly across the sky. pub time_scale: f64, } impl Default for GameUnitsToCelestial { fn default() -> Self { Self { origin_latitude: 0.0, origin_longitude: 0.0, heading: 0.0, time_scale: 1.0, initial_julian_date: 2451544.5, } } } type DrawStarfield = ( SetItemPipeline, SetMeshViewBindGroup<0>, StarfieldRenderCommand, ); #[derive(Default, Clone, Resource, ExtractResource, Reflect, ShaderType)] #[reflect(Reso urce)] struct StarfieldUniform { pub world_to_ecef: Mat3, pub sidereal_time: f32, } #[derive(Resource, Default)] struct StarfieldUniformBuffer { buffer: UniformBuffer, } #[derive(Component)] struct StarfieldBindGroup(BindGroup); /// Render a sky filled with stars. pub struct StarfieldPlugin; impl Plugin for StarfieldPlugin { fn build(&self, app: &mut App) { let mut shaders = app.world.resource_mut::>(); let starfield_shader = Shader::from_wgsl(include_str!("shader.wgsl")); shaders.set_untracked(STARFIELD_SHADER_HANDLE, starfield_shader); app.insert_resource(ClearColor(Color::BLACK)) .init_resource::() .init_resource::(); if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { render_app .init_resource::() .init_resource::() .init_resource::>() .add_system(extract_starfield.in_schedule(ExtractSchedule)) .add_system(prepare_starfield.in_set(RenderSet::Prepare)) .add_system(queue_starfield.in_set(RenderSet::Queue)) .add_render_command::(); } } } fn extract_starfield(mut commands: Commands, r: Extract>) { commands.insert_resource(r.clone()) } fn prepare_starfield( render_device: Res, render_queue: Res, mut starfield_buffer: ResMut, game_units_to_celestial: Res, time: Res