feat: BlackHoleUniforms + camera/params mirror system
This commit is contained in:
parent
1a2b157ef3
commit
265ec9925d
@ -1,11 +1,36 @@
|
||||
#import bevy_sprite::mesh2d_vertex_output::VertexOutput
|
||||
|
||||
@group(#{MATERIAL_BIND_GROUP}) @binding(0) var<uniform> time: f32;
|
||||
struct BlackHoleUniforms {
|
||||
eye: vec4<f32>,
|
||||
forward: vec4<f32>,
|
||||
right: vec4<f32>,
|
||||
up: vec4<f32>,
|
||||
resolution: vec2<f32>,
|
||||
time: f32,
|
||||
_pad3: f32,
|
||||
rs: f32,
|
||||
disk_inner: f32,
|
||||
disk_outer: f32,
|
||||
disk_tilt: f32,
|
||||
disk_brightness: f32,
|
||||
disk_rotation_speed: f32,
|
||||
doppler_strength: f32,
|
||||
star_intensity: f32,
|
||||
skybox_intensity: f32,
|
||||
grid_density: f32,
|
||||
doppler_enabled: u32,
|
||||
grid_enabled: u32,
|
||||
planet_count: u32,
|
||||
steps: u32,
|
||||
_pad4: f32,
|
||||
_pad5: f32,
|
||||
};
|
||||
|
||||
@group(#{MATERIAL_BIND_GROUP}) @binding(0) var<uniform> uniforms: BlackHoleUniforms;
|
||||
|
||||
@fragment
|
||||
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||
// Gradient from time, just to prove the uniform flows.
|
||||
let t = (sin(time) + 1.0) * 0.5;
|
||||
let col = mix(vec3<f32>(0.02, 0.02, 0.05), vec3<f32>(0.08, 0.04, 0.12), t);
|
||||
return vec4<f32>(col, 1.0);
|
||||
// Prove the camera basis + uniforms flow: tint by eye direction.
|
||||
let n = normalize(uniforms.eye.xyz);
|
||||
return vec4<f32>(abs(n) * 0.5 + 0.3, 1.0);
|
||||
}
|
||||
|
||||
@ -1,13 +1,105 @@
|
||||
use bevy::prelude::*;
|
||||
use bevy::reflect::TypePath;
|
||||
use bevy::render::render_resource::AsBindGroup;
|
||||
use bevy::render::render_resource::{AsBindGroup, ShaderType};
|
||||
use bevy::render::storage::ShaderBuffer;
|
||||
use bevy::shader::ShaderRef;
|
||||
use bevy::sprite_render::Material2d;
|
||||
|
||||
#[derive(Asset, TypePath, AsBindGroup, Debug, Clone)]
|
||||
/// GPU uniform: params + camera packed into one struct bound at binding 0.
|
||||
#[derive(Clone, ShaderType)]
|
||||
pub struct BlackHoleUniforms {
|
||||
// Camera basis + eye (4 vec3s = must align; pad each to vec4 via the shader struct)
|
||||
pub eye: Vec3,
|
||||
pub _pad0: f32,
|
||||
pub forward: Vec3,
|
||||
pub _pad1: f32,
|
||||
pub right: Vec3,
|
||||
pub _pad2: f32,
|
||||
pub up: Vec3,
|
||||
pub fov: f32,
|
||||
// Resolution
|
||||
pub resolution: Vec2,
|
||||
pub time: f32,
|
||||
pub _pad3: f32,
|
||||
// Physics + disk
|
||||
pub rs: f32,
|
||||
pub disk_inner: f32,
|
||||
pub disk_outer: f32,
|
||||
pub disk_tilt: f32,
|
||||
pub disk_brightness: f32,
|
||||
pub disk_rotation_speed: f32,
|
||||
pub doppler_strength: f32,
|
||||
pub star_intensity: f32,
|
||||
pub skybox_intensity: f32,
|
||||
pub grid_density: f32,
|
||||
// Flags packed as u32 (bools aren't valid uniform scalar types in WGSL)
|
||||
pub doppler_enabled: u32,
|
||||
pub grid_enabled: u32,
|
||||
pub planet_count: u32,
|
||||
pub steps: u32,
|
||||
pub _pad4: f32,
|
||||
pub _pad5: f32,
|
||||
}
|
||||
|
||||
impl Default for BlackHoleUniforms {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
eye: Vec3::new(0.0, 0.0, 30.0),
|
||||
_pad0: 0.0,
|
||||
forward: Vec3::new(0.0, 0.0, -1.0),
|
||||
_pad1: 0.0,
|
||||
right: Vec3::new(1.0, 0.0, 0.0),
|
||||
_pad2: 0.0,
|
||||
up: Vec3::new(0.0, 1.0, 0.0),
|
||||
fov: 1.0,
|
||||
resolution: Vec2::new(1280.0, 720.0),
|
||||
time: 0.0,
|
||||
_pad3: 0.0,
|
||||
rs: 1.0,
|
||||
disk_inner: 3.0,
|
||||
disk_outer: 15.0,
|
||||
disk_tilt: 1.318,
|
||||
disk_brightness: 1.0,
|
||||
disk_rotation_speed: 0.5,
|
||||
doppler_strength: 1.0,
|
||||
star_intensity: 1.0,
|
||||
skybox_intensity: 0.0,
|
||||
grid_density: 1.0,
|
||||
doppler_enabled: 1,
|
||||
grid_enabled: 0,
|
||||
planet_count: 0,
|
||||
steps: 300,
|
||||
_pad4: 0.0,
|
||||
_pad5: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// One planet's data, uploaded in a storage buffer (binding 3).
|
||||
#[derive(Clone, Copy, ShaderType, Default)]
|
||||
pub struct SphereData {
|
||||
pub center: Vec3,
|
||||
pub radius: f32,
|
||||
pub color: Vec3,
|
||||
pub emissive: u32,
|
||||
pub _pad0: f32,
|
||||
pub _pad1: f32,
|
||||
pub _pad2: f32,
|
||||
}
|
||||
|
||||
pub const MAX_PLANETS: usize = 32;
|
||||
|
||||
#[derive(Asset, TypePath, AsBindGroup, Clone)]
|
||||
pub struct BlackHoleMaterial {
|
||||
#[uniform(0)]
|
||||
pub time: f32,
|
||||
pub uniforms: BlackHoleUniforms,
|
||||
// Texture at binding 1 + its matching sampler at binding 2. The derive
|
||||
// requires the texture and sampler attributes to live on the same field.
|
||||
#[texture(1)]
|
||||
#[sampler(2)]
|
||||
pub skybox: Option<Handle<Image>>,
|
||||
#[storage(3, read_only)]
|
||||
pub planets: Handle<ShaderBuffer>,
|
||||
}
|
||||
|
||||
impl Material2d for BlackHoleMaterial {
|
||||
@ -15,3 +107,13 @@ impl Material2d for BlackHoleMaterial {
|
||||
"shaders/black_hole.wgsl".into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for BlackHoleMaterial {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
uniforms: BlackHoleUniforms::default(),
|
||||
skybox: None,
|
||||
planets: Handle::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,12 +7,11 @@ pub struct BlackHolePlugin;
|
||||
|
||||
impl Plugin for BlackHolePlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_plugins(Material2dPlugin::<BlackHoleMaterial>::default())
|
||||
.add_systems(Startup, spawn_fullscreen_quad)
|
||||
.add_systems(Update, update_time)
|
||||
.init_resource::<crate::camera::OrbitCamera>()
|
||||
app.init_resource::<crate::camera::OrbitCamera>()
|
||||
.init_resource::<crate::params::BlackHoleParams>()
|
||||
.add_systems(Update, crate::camera::orbit_controller);
|
||||
.add_plugins(Material2dPlugin::<BlackHoleMaterial>::default())
|
||||
.add_systems(Startup, spawn_fullscreen_quad)
|
||||
.add_systems(Update, (crate::camera::orbit_controller, mirror_params));
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,17 +19,56 @@ fn spawn_fullscreen_quad(
|
||||
mut commands: Commands,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<BlackHoleMaterial>>,
|
||||
window: Query<&Window>,
|
||||
) {
|
||||
commands.spawn(Camera2d);
|
||||
let win = match window.single() {
|
||||
Ok(w) => w,
|
||||
Err(_) => return,
|
||||
};
|
||||
let aspect = win.width() / win.height();
|
||||
commands.spawn((
|
||||
Mesh2d(meshes.add(Rectangle::new(2.0, 2.0))),
|
||||
MeshMaterial2d(materials.add(BlackHoleMaterial { time: 0.0 })),
|
||||
Mesh2d(meshes.add(Rectangle::new(2.0 * aspect, 2.0))),
|
||||
MeshMaterial2d(materials.add(BlackHoleMaterial::default())),
|
||||
Transform::default(),
|
||||
));
|
||||
commands.spawn(Camera2d);
|
||||
}
|
||||
|
||||
fn update_time(time: Res<Time>, mut materials: ResMut<Assets<BlackHoleMaterial>>) {
|
||||
fn mirror_params(
|
||||
camera: Res<crate::camera::OrbitCamera>,
|
||||
params: Res<crate::params::BlackHoleParams>,
|
||||
time: Res<Time>,
|
||||
window: Query<&Window>,
|
||||
mut materials: ResMut<Assets<BlackHoleMaterial>>,
|
||||
) {
|
||||
let win = match window.single() {
|
||||
Ok(w) => w,
|
||||
Err(_) => return,
|
||||
};
|
||||
// Only update when something changed.
|
||||
let (eye, forward, right, up) = camera.basis();
|
||||
for (_, mat) in materials.iter_mut() {
|
||||
mat.time = time.elapsed_secs();
|
||||
let u = &mut mat.uniforms;
|
||||
u.eye = eye;
|
||||
u.forward = forward;
|
||||
u.right = right;
|
||||
u.up = up;
|
||||
u.fov = camera.fov;
|
||||
u.resolution = Vec2::new(win.width(), win.height());
|
||||
u.time = time.elapsed_secs();
|
||||
u.rs = params.rs;
|
||||
u.disk_inner = params.disk_inner;
|
||||
u.disk_outer = params.disk_outer;
|
||||
u.disk_tilt = params.disk_tilt;
|
||||
u.disk_brightness = params.disk_brightness;
|
||||
u.disk_rotation_speed = params.disk_rotation_speed;
|
||||
u.doppler_strength = params.doppler_strength;
|
||||
u.star_intensity = params.star_intensity;
|
||||
u.skybox_intensity = params.skybox_intensity;
|
||||
u.grid_density = params.grid_density;
|
||||
u.doppler_enabled = params.doppler_enabled as u32;
|
||||
u.grid_enabled = params.grid_enabled as u32;
|
||||
u.planet_count = params.planet_count;
|
||||
u.steps = params.steps;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user