From 5894a2443ce58638901f13da8255a008998ddd5b Mon Sep 17 00:00:00 2001 From: hut Date: Mon, 1 Apr 2024 17:19:43 +0200 Subject: [PATCH] center coordinate system of renderer at player camera this avoids rendering glitches when camera is far away from the center of the coordinate system. --- src/commands.rs | 21 +++++++---------- src/world.rs | 62 ++++++++++++++++++++++++++++++++++++------------- 2 files changed, 54 insertions(+), 29 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index f13b465..d259fff 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -34,7 +34,7 @@ struct ParserState { // Actor fields id: String, - pos: Vec3, + pos: DVec3, model: String, model_scale: f32, rotation: Quat, @@ -84,7 +84,7 @@ impl Default for ParserState { chat: "".to_string(), id: "".to_string(), - pos: Vec3::new(0.0, 0.0, 0.0), + pos: DVec3::new(0.0, 0.0, 0.0), model: "".to_string(), model_scale: 1.0, rotation: Quat::IDENTITY, @@ -205,8 +205,8 @@ pub fn load_defs( state.class = DefClass::Actor; state.model = model.to_string(); if let (Ok(x_float), Ok(y_float), Ok(z_float)) = - (x.parse::(), y.parse::(), z.parse::()) { - state.pos = Vec3::new(x_float, y_float, z_float); + (x.parse::(), y.parse::(), z.parse::()) { + state.pos = DVec3::new(x_float, y_float, z_float); } else { error!("Can't parse coordinates as floats in def: {line}"); @@ -506,6 +506,8 @@ fn spawn_entities( camdistance: state.camdistance, ..default() }); + actor.insert(Position::from(state.pos)); + actor.insert(Rotation::from(state.rotation)); if state.is_sphere { let sphere_texture_handle: Handle = asset_server.load(format!("textures/{}.jpg", state.model)); let sphere_handle = meshes.add(Sphere::default().mesh().uv(128, 128)); @@ -519,18 +521,16 @@ fn spawn_entities( mesh: sphere_handle, material: sphere_material_handle, transform: Transform { - translation: state.pos, scale: Vec3::splat(state.model_scale), - rotation: state.rotation, + ..default() }, ..default() }); } else { actor.insert(SceneBundle { transform: Transform { - translation: state.pos, scale: Vec3::splat(state.model_scale), - rotation: state.rotation, + ..default() }, scene: asset_server.load(world::asset_name_to_path(state.model.as_str())), ..default() @@ -582,11 +582,6 @@ fn spawn_entities( radius: 100.0, ..default() }, - transform: Transform { - translation: state.pos, - scale: Vec3::splat(state.model_scale), - rotation: state.rotation, - }, ..default() }); } diff --git a/src/world.rs b/src/world.rs index edd41ff..e0486e4 100644 --- a/src/world.rs +++ b/src/world.rs @@ -4,6 +4,7 @@ use bevy::pbr::CascadeShadowConfigBuilder; use bevy::render::render_resource::{AsBindGroup, ShaderRef}; use bevy::math::DVec3; use bevy_xpbd_3d::prelude::*; +use bevy_xpbd_3d::plugins::sync::SyncConfig; use std::f32::consts::PI; const ASTEROID_SIZE: f32 = 100.0; @@ -35,6 +36,14 @@ impl Plugin for WorldPlugin { app.add_plugins(MaterialPlugin::::default()); //app.add_plugins(PhysicsDebugPlugin::default()); app.insert_resource(Gravity(DVec3::splat(0.0))); + + // Disable bevy_xpbd's position->transform sync because we have a + // custom syncing function. + app.insert_resource(SyncConfig { + position_to_transform: false, + transform_to_position: false, + }); + app.add_systems(PreUpdate, position_to_transform); } } @@ -153,17 +162,19 @@ pub fn setup( // Add shaded ring let ring_radius = 640000.0; let jupiter_radius = 200000.0; - commands.spawn(MaterialMeshBundle { - mesh: meshes.add(Mesh::from(Cylinder::new(ring_radius, 1.0))), - transform: Transform::from_xyz(300000.0, -1000.0, 500000.0) - .with_rotation(Quat::from_rotation_z(1f32.to_radians())), - material: materials_custom.add(RingMaterial { - alpha_mode: AlphaMode::Blend, - ring_radius: ring_radius, - jupiter_radius: jupiter_radius, - }), - ..default() - }); + commands.spawn(( + MaterialMeshBundle { + mesh: meshes.add(Mesh::from(Cylinder::new(ring_radius, 1.0))), + material: materials_custom.add(RingMaterial { + alpha_mode: AlphaMode::Blend, + ring_radius: ring_radius, + jupiter_radius: jupiter_radius, + }), + ..default() + }, + Position::from_xyz(300000.0, -1000.0, 500000.0), + Rotation::from(Quat::from_rotation_z(1f32.to_radians())), + )); // Add Light from the Sun commands.spawn(DirectionalLightBundle { @@ -185,23 +196,23 @@ pub fn setup( fn handle_cheats( key_input: Res>, - mut q_player: Query<(&mut Transform, &mut LinearVelocity), With>, + mut q_player: Query<(&Transform, &mut Position, &mut LinearVelocity), With>, mut q_life: Query<(&mut actor::LifeForm, ), With>, settings: ResMut, ) { if !settings.dev_mode || q_player.is_empty() || q_life.is_empty() { return; } - let (mut trans, mut v) = q_player.get_single_mut().unwrap(); + let (trans, mut pos, mut v) = q_player.get_single_mut().unwrap(); let (mut lifeform, ) = q_life.get_single_mut().unwrap(); if key_input.just_pressed(settings.key_cheat_pizza) { - trans.translation = Vec3::new(-3370.0, 0.0, 0.0); + pos.0 = DVec3::new(-3370.0, 0.0, 0.0); } if key_input.just_pressed(settings.key_cheat_farview1) { - trans.translation = Vec3::new(-800000.0, 800000.0, 0.0); + pos.0 = DVec3::new(-800000.0, 800000.0, 0.0); } if key_input.just_pressed(settings.key_cheat_farview2) { - trans.translation = Vec3::new(800000.0, 400000.0, 0.0); + pos.0 = DVec3::new(800000.0, 400000.0, 0.0); } if key_input.just_pressed(settings.key_cheat_stop) { v.0 = DVec3::ZERO; @@ -219,3 +230,22 @@ fn handle_cheats( lifeform.adrenaline = 1.0; } } + +// A variant of bevy_xpbd_3d::plugins::position_to_transform that adjusts +// the rendering position to center entities at the player camera. +// This avoids rendering glitches when very far away from the origin. +pub fn position_to_transform( + q_player: Query<&Position, With>, + mut q_trans: Query<(&mut Transform, &Position, &Rotation)>, +) { + if let Ok(player_pos) = q_player.get_single() { + for (mut transform, pos, rot) in &mut q_trans { + transform.translation = Vec3::new( + (pos.x - player_pos.x) as f32, + (pos.y - player_pos.y) as f32, + (pos.z - player_pos.z) as f32, + ); + transform.rotation = rot.as_quat(); + } + } +}