This commit is contained in:
Leon Liu 2025-08-18 01:12:45 +09:00
parent e83da3156b
commit bd37295da9

View File

@ -6,10 +6,6 @@ use bevy::{
};
use bevy_inspector_egui::{bevy_egui::EguiPlugin, quick::WorldInspectorPlugin};
use bevy_panorbit_camera::{PanOrbitCamera, PanOrbitCameraPlugin};
use big_space::{
plugin::BigSpaceDefaultPlugins,
prelude::{BigSpaceCommands, FloatingOrigin},
};
use iyes_perf_ui::{PerfUiPlugin, prelude::*};
use solar_sim::InitialState;
@ -118,14 +114,7 @@ impl Plugin for SolarRenderingPlugin {
PostUpdate,
(update_label_positions.after(manage_label_overlaps),),
)
.add_systems(
Update,
(
handle_label_clicks,
handle_speed_controls,
enhance_sun_emissive_with_retry,
),
);
.add_systems(Update, (handle_label_clicks, handle_speed_controls));
}
}
@ -133,18 +122,39 @@ fn sync_position_to_transform(
mut query: Query<(Entity, &Position, &mut Transform)>,
origin: Res<Origin>,
) {
// let offset = origin.target.map_or(DVec3::ZERO, |target| {
// query
// .get(target)
// .map_or(DVec3::ZERO, |(_, position, _)| position.0.0)
// });
let offset = DVec3::ZERO;
let offset = origin.target.map_or(DVec3::ZERO, |target| {
query
.get(target)
.map_or(DVec3::ZERO, |(_, position, _)| position.0.0)
});
for (_, position, mut transform) in query.iter_mut() {
transform.translation = ((position.0.0 - offset) * AU_TO_GAME_UNITS).as_vec3();
}
}
fn setup_rendering(mut commands: Commands) {
// Spawn camera with pan/orbit/zoom controls
// Place it at a good distance to view the solar system
commands.spawn((
PanOrbitCamera {
zoom_lower_limit: 1e-6,
..default()
},
Camera {
hdr: true,
clear_color: ClearColorConfig::Custom(Color::BLACK),
..default()
},
Projection::Perspective(PerspectiveProjection {
near: 1e-8, // Very close near plane for extreme zooming
far: 1e-2,
..default()
}),
Tonemapping::TonyMcMapface,
Transform::from_translation(Vec3::new(0., 0., 10.0)),
Bloom::NATURAL,
));
commands.spawn(PerfUiAllEntries::default());
}
@ -374,208 +384,86 @@ fn handle_speed_controls(
}
}
fn enhance_sun_emissive_with_retry(
mut commands: Commands,
mesh_query: Query<&MeshMaterial3d<StandardMaterial>>,
mut sun_query: Query<
(Entity, &Children, Option<&mut EmissiveEnhancementAttempts>),
(
With<Star>,
With<NeedsEmissiveEnhancement>,
Without<EmissiveEnhanced>,
),
>,
children_query: Query<&Children>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
for (sun_entity, children, attempts_opt) in sun_query.iter_mut() {
// Initialize attempts tracking if not present
let mut attempts = if let Some(mut att) = attempts_opt {
att.attempts += 1;
att.attempts
} else {
// First attempt, add the component
commands
.entity(sun_entity)
.insert(EmissiveEnhancementAttempts {
attempts: 1,
max_attempts: 300, // Try for ~5 seconds at 60fps
});
1
};
// Only try every 10 frames to avoid spam
if attempts % 10 != 0 {
continue;
}
info!("Attempting sun emissive enhancement (attempt {})", attempts);
// Try to enhance the sun's emissive material
let enhanced =
enhance_emissive_for_children(children, &children_query, &mesh_query, &mut materials);
if enhanced {
info!("Successfully enhanced sun emissive material!");
// Mark this sun as enhanced to avoid repeated processing
commands.entity(sun_entity).insert(EmissiveEnhanced);
commands
.entity(sun_entity)
.remove::<NeedsEmissiveEnhancement>();
commands
.entity(sun_entity)
.remove::<EmissiveEnhancementAttempts>();
} else if attempts >= 300 {
// Give up after max attempts
info!(
"Giving up on sun emissive enhancement after {} attempts",
attempts
);
commands
.entity(sun_entity)
.remove::<NeedsEmissiveEnhancement>();
commands
.entity(sun_entity)
.remove::<EmissiveEnhancementAttempts>();
}
}
}
fn enhance_emissive_for_children(
children: &Children,
children_query: &Query<&Children>,
mesh_query: &Query<&MeshMaterial3d<StandardMaterial>>,
materials: &mut ResMut<Assets<StandardMaterial>>,
) -> bool {
let mut enhanced_any = false;
for child in children.iter() {
// Try to enhance material for this child if it has a mesh
if let Ok(material_handle) = mesh_query.get(child) {
if let Some(material) = materials.get_mut(&material_handle.0) {
// Enhance emissive properties while preserving existing textures
// Set emissive to bright white to enhance the existing emissive texture
info!("Enhanced material for child entity!");
material.emissive = LinearRgba::rgb(200.0, 200.0, 200.0);
// Keep all existing textures (base_color_texture, emissive_texture, etc.)
enhanced_any = true;
}
}
// Recursively check this child's children
if let Ok(grandchildren) = children_query.get(child) {
if enhance_emissive_for_children(grandchildren, children_query, mesh_query, materials) {
enhanced_any = true;
}
}
}
enhanced_any
}
const AU_TO_KM: f64 = 149597870.691;
fn setup_solar_system(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn_big_space_default(|commands| {
commands.spawn((
PanOrbitCamera {
zoom_lower_limit: 1e-6,
..default()
// Load initial state from RON file
let initial_state_content = match std::fs::read_to_string("assets/initial_state.ron") {
Ok(content) => content,
Err(err) => {
error!("Failed to read initial_state.ron: {}", err);
return;
}
};
let initial_state: InitialState = match ron::from_str(&initial_state_content) {
Ok(state) => state,
Err(err) => {
error!("Failed to parse initial_state.ron: {}", err);
return;
}
};
for body_data in initial_state.bodies {
// Convert radius from km to AU
let radius_au = body_data.radius / AU_TO_KM; // km to AU conversion
// Convert mass from kg to solar masses
let mass_solar = body_data.mass / SOLAR_MASS_KG;
// Create base bundle
let mut entity_commands = commands.spawn((
ObjectBundle {
name: Name(ObjectName(body_data.name.clone())),
position: Position(PositionAu(DVec3::new(
body_data.position.0,
body_data.position.1,
body_data.position.2,
))),
velocity: Velocity(VelocityAuPerDay(DVec3::new(
body_data.velocity.0,
body_data.velocity.1,
body_data.velocity.2,
))),
mass: Mass(MassSolarMass(mass_solar)),
radius: Radius(DistanceAu(radius_au)),
},
Camera {
hdr: true,
clear_color: ClearColorConfig::Custom(Color::BLACK),
..default()
},
Projection::Perspective(PerspectiveProjection {
near: 1e-8, // Very close near plane for extreme zooming
far: 1e-2,
..default()
}),
Tonemapping::TonyMcMapface,
Transform::from_translation(Vec3::new(0., 0., 10.0)),
Bloom::NATURAL,
FloatingOrigin,
Trackable {},
Transform::default(),
Visibility::default(),
));
let scene_handle = asset_server.load(format!("models/{}#Scene0", body_data.model.path));
entity_commands.with_child((
SceneRoot(scene_handle.clone()),
Transform::from_scale(
Vec3::new(
body_data.model.scale.0,
body_data.model.scale.1,
body_data.model.scale.2,
) / AU_TO_KM as f32
* 10000.,
),
));
// Load initial state from RON file
let initial_state_content = match std::fs::read_to_string("assets/initial_state.ron") {
Ok(content) => content,
Err(err) => {
error!("Failed to read initial_state.ron: {}", err);
return;
// Add special components for Sun and Earth
match body_data.name.as_str() {
"Sun" => {
entity_commands.insert(Star);
entity_commands.insert(NeedsEmissiveEnhancement);
entity_commands.insert(PointLight {
color: Color::WHITE,
shadows_enabled: true,
..default()
});
}
};
let initial_state: InitialState = match ron::from_str(&initial_state_content) {
Ok(state) => state,
Err(err) => {
error!("Failed to parse initial_state.ron: {}", err);
return;
"Earth" => {
entity_commands.insert(Earth);
}
};
for body_data in initial_state.bodies {
// Convert radius from km to AU
let radius_au = body_data.radius / AU_TO_KM; // km to AU conversion
// Convert mass from kg to solar masses
let mass_solar = body_data.mass / SOLAR_MASS_KG;
// Create base bundle
let mut entity_commands = commands.spawn((
ObjectBundle {
name: Name(ObjectName(body_data.name.clone())),
position: Position(PositionAu(DVec3::new(
body_data.position.0,
body_data.position.1,
body_data.position.2,
))),
velocity: Velocity(VelocityAuPerDay(DVec3::new(
body_data.velocity.0,
body_data.velocity.1,
body_data.velocity.2,
))),
mass: Mass(MassSolarMass(mass_solar)),
radius: Radius(DistanceAu(radius_au)),
},
Trackable {},
Transform::default(),
Visibility::default(),
));
let scene_handle = asset_server.load(format!("models/{}#Scene0", body_data.model.path));
entity_commands.with_child((
SceneRoot(scene_handle.clone()),
Transform::from_scale(
Vec3::new(
body_data.model.scale.0,
body_data.model.scale.1,
body_data.model.scale.2,
) / AU_TO_KM as f32
* 10000.,
),
));
// Add special components for Sun and Earth
match body_data.name.as_str() {
"Sun" => {
entity_commands.insert(Star);
entity_commands.insert(NeedsEmissiveEnhancement);
entity_commands.insert(PointLight {
color: Color::WHITE,
shadows_enabled: true,
..default()
});
}
"Earth" => {
entity_commands.insert(Earth);
}
_ => {}
}
info!("Spawned celestial body: {}", body_data.name);
_ => {}
}
});
info!("Spawned celestial body: {}", body_data.name);
}
}
// High precision constants
@ -673,20 +561,15 @@ fn n_body(mut query: Query<(&Mass, &mut Position, &mut Velocity)>) {
fn main() {
App::new()
.add_plugins(
DefaultPlugins
.set(WindowPlugin {
primary_window: Some(Window {
title: "Solar Sim".to_string(),
mode: WindowMode::BorderlessFullscreen(MonitorSelection::Primary),
resolution: WindowResolution::default().with_scale_factor_override(2.0),
..default()
}),
..default()
})
.disable::<TransformPlugin>(),
)
.add_plugins(BigSpaceDefaultPlugins)
.add_plugins(DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
title: "Solar Sim".to_string(),
mode: WindowMode::BorderlessFullscreen(MonitorSelection::Primary),
resolution: WindowResolution::default().with_scale_factor_override(2.0),
..default()
}),
..default()
}))
.add_plugins(EguiPlugin::default())
.add_plugins(PanOrbitCameraPlugin)
.register_type::<Name>()