use parallel iter to update velocities

This commit is contained in:
Joe Ardent 2024-11-27 13:40:01 -08:00
parent c366dc3ec6
commit 5158fba63b
3 changed files with 86 additions and 69 deletions

BIN
assets/models/toid3.glb Normal file

Binary file not shown.

View file

@ -1,6 +1,7 @@
use argh::FromArgs; use argh::FromArgs;
use bevy::{ use bevy::{
prelude::*, prelude::*,
tasks::ParallelIterator,
utils::{HashMap, HashSet}, utils::{HashMap, HashSet},
}; };
use bevy_spatial::{kdtree::KDTree3, SpatialAccess}; use bevy_spatial::{kdtree::KDTree3, SpatialAccess};
@ -8,7 +9,7 @@ use bevy_spatial::{kdtree::KDTree3, SpatialAccess};
pub type NNTree = KDTree3<Toid>; pub type NNTree = KDTree3<Toid>;
// toid stuff // toid stuff
const SPEED: f32 = 10.0; const SPEED: f32 = 15.0;
const SPEED_DIFF_RANGE: f32 = 0.1; // +/- 10% const SPEED_DIFF_RANGE: f32 = 0.1; // +/- 10%
const MAX_DELTA_V: f32 = std::f32::consts::PI * 2.0; // basically 360 degrees/sec const MAX_DELTA_V: f32 = std::f32::consts::PI * 2.0; // basically 360 degrees/sec
@ -16,9 +17,9 @@ const MAX_DELTA_V: f32 = std::f32::consts::PI * 2.0; // basically 360 degrees/se
const RADIUS: f32 = 50.0; const RADIUS: f32 = 50.0;
// how close to try to stay to your buddies // how close to try to stay to your buddies
const BUDDY_RADIUS: f32 = 10.0; const BUDDY_RADIUS: f32 = SPEED;
const MIN_ALTITUDE: f32 = 3.5; const MIN_ALTITUDE: f32 = 13.5;
#[derive(Debug, FromArgs, Resource)] #[derive(Debug, FromArgs, Resource)]
/// Toid Watching /// Toid Watching
@ -43,6 +44,9 @@ pub struct Toid {
pub buddies: usize, pub buddies: usize,
} }
#[derive(Resource, Debug, Deref, DerefMut, Clone, Default)]
pub struct Paused(bool);
#[derive(Debug, Default, Clone, Copy, Deref, DerefMut, Resource)] #[derive(Debug, Default, Clone, Copy, Deref, DerefMut, Resource)]
pub struct LookAt(Vec3); pub struct LookAt(Vec3);
@ -60,7 +64,6 @@ pub fn turkey_time(
let y = r.gen_range(0.1..=5.5); let y = r.gen_range(0.1..=5.5);
let pos = Vec3::new(x, MIN_ALTITUDE + y, z); let pos = Vec3::new(x, MIN_ALTITUDE + y, z);
let xform = Transform::from_translation(pos); let xform = Transform::from_translation(pos);
//dbg!(xform);
let spatial_bundle = (xform, Visibility::Visible); let spatial_bundle = (xform, Visibility::Visible);
commands commands
.spawn(spatial_bundle) .spawn(spatial_bundle)
@ -68,10 +71,6 @@ pub fn turkey_time(
.with_children(|t| { .with_children(|t| {
t.spawn(SceneRoot(scene.to_owned())) t.spawn(SceneRoot(scene.to_owned()))
.insert(Transform::default()); .insert(Transform::default());
// .insert(Transform::from_rotation(Quat::from_axis_angle(
// Vec3::Y,
// -std::f32::consts::FRAC_PI_2,
// )));
}) })
.id() .id()
} }
@ -81,72 +80,79 @@ pub fn update_vel(
time: Res<Time>, time: Res<Time>,
positions: Res<Positions>, positions: Res<Positions>,
index: Res<NNTree>, index: Res<NNTree>,
paused: Res<Paused>,
) { ) {
if **paused {
return;
}
let dt = time.delta_secs(); let dt = time.delta_secs();
let max_delta = MAX_DELTA_V * dt; let max_delta = MAX_DELTA_V * dt;
for (xform, mut vel, toid, buddies, entity) in toids.iter_mut() { toids
let speed = toid.speed; .par_iter_mut()
let mut dir = vel.normalize(); .for_each(|(xform, mut vel, toid, buddies, entity)| {
let pos = xform.translation; let speed = toid.speed;
let original_dir = dir; let mut dir = vel.normalize();
let pos = xform.translation;
let original_dir = dir;
// find buddies and orient; point more towards further-away buddies // find buddies and orient; point more towards further-away buddies
for buddy in buddies.iter() { for buddy in buddies.iter() {
let bp = positions.get(buddy).unwrap(); let bp = positions.get(buddy).unwrap();
let bdir = *bp - pos; let bdir = *bp - pos;
let dist = bdir.length(); let dist = bdir.length();
let rot = Quat::from_rotation_arc(dir, bdir.normalize()); let rot = Quat::from_rotation_arc(dir, bdir.normalize());
let s = (dist / (BUDDY_RADIUS * 1.2)).min(1.0); let s = (dist / (BUDDY_RADIUS * 1.2)).min(1.0);
let rot = Quat::IDENTITY.slerp(rot, s); let rot = Quat::IDENTITY.slerp(rot, s);
dir = rot.mul_vec3(dir).normalize(); dir = rot.mul_vec3(dir).normalize();
} }
// avoid flying into neighbors // avoid flying into neighbors
let min_dist = speed * 10.0; let min_dist = speed * 20.0;
for neighbor in index for neighbor in index
.within_distance(pos, min_dist) .within_distance(pos, min_dist)
.iter() .iter()
.filter(|n| n.1.is_some() && n.1.unwrap() != entity) .filter(|n| n.1.is_some() && n.1.unwrap() != entity)
{ {
let bp = neighbor.0; let bp = neighbor.0;
let bdir = pos - bp; let bdir = pos - bp;
let dist = bdir.length(); let dist = bdir.length();
let s = 1.0 - (dist / min_dist).min(1.0); let s = 1.0 - (dist / min_dist).min(1.0);
let rot = Quat::from_rotation_arc(dir, bdir.normalize()); let rot = Quat::from_rotation_arc(dir, bdir.normalize());
let rot = Quat::IDENTITY.slerp(rot, s); let rot = Quat::IDENTITY.slerp(rot, s);
dir = rot.mul_vec3(dir).normalize(); dir = rot.mul_vec3(dir).normalize();
} }
// nudge toward origin if too far // nudge toward origin if too far
{ {
let dist = pos.length(); let dist = pos.length();
let toward_origin = -pos.normalize(); let toward_origin = -pos.normalize();
let s = (dist / RADIUS).min(1.0); let s = (dist / RADIUS).min(1.0);
let rot = Quat::from_rotation_arc(dir, toward_origin); let rot = Quat::from_rotation_arc(dir, toward_origin);
let rot = Quat::IDENTITY.slerp(rot, s); let rot = Quat::IDENTITY.slerp(rot, s);
dir = rot.mul_vec3(dir).normalize(); dir = rot.mul_vec3(dir).normalize();
} }
// nudge up if too low // nudge up if too low
if pos.y < MIN_ALTITUDE { if pos.y < MIN_ALTITUDE {
let dh = MIN_ALTITUDE - pos.y; let dh = MIN_ALTITUDE - pos.y;
let s = (dh / MIN_ALTITUDE).min(1.0); let s = (dh / MIN_ALTITUDE).min(1.0);
let rot = Quat::from_rotation_arc(dir, Vec3::Y); let rot = Quat::from_rotation_arc(dir, Vec3::Y);
let rot = Quat::IDENTITY.slerp(rot, s); let rot = Quat::IDENTITY.slerp(rot, s);
dir = rot.mul_vec3(dir).normalize(); dir = rot.mul_vec3(dir).normalize();
} }
// make sure velocity doesn't change too suddenly // make sure velocity doesn't change too suddenly
let delta = dir.dot(original_dir).acos(); let delta = dir.dot(original_dir).acos();
if delta > max_delta { if delta > max_delta {
let s = max_delta / delta; let s = max_delta / delta;
let rot = Quat::from_rotation_arc(original_dir, dir); let rot = Quat::from_rotation_arc(original_dir, dir);
let rot = Quat::IDENTITY.slerp(rot, s); let rot = Quat::IDENTITY.slerp(rot, s);
dir = rot.mul_vec3(original_dir).normalize(); dir = rot.mul_vec3(original_dir).normalize();
} }
**vel = dir * speed; **vel = dir * speed;
} });
} }
pub fn update_pos( pub fn update_pos(
@ -154,7 +160,12 @@ pub fn update_pos(
mut positions: ResMut<Positions>, mut positions: ResMut<Positions>,
mut lookat: ResMut<LookAt>, mut lookat: ResMut<LookAt>,
time: Res<Time>, time: Res<Time>,
paused: Res<Paused>,
) { ) {
if **paused {
return;
}
let mut new_look = Vec3::ZERO; let mut new_look = Vec3::ZERO;
let dt = time.delta_secs(); let dt = time.delta_secs();
for (mut xform, vel, entity) in toids.iter_mut() { for (mut xform, vel, entity) in toids.iter_mut() {
@ -204,13 +215,14 @@ pub fn update_gizmos(toids: Query<&Transform, With<Toid>>, mut gizmos: Gizmos) {
let forward = toid.forward().as_vec3(); let forward = toid.forward().as_vec3();
let right = toid.right().as_vec3(); let right = toid.right().as_vec3();
gizmos.ray(pos, pos + forward, Color::srgb_u8(255, 0, 0)); gizmos.ray(pos, pos + forward, Color::srgb_u8(255, 0, 0));
//gizmos.ray(pos, pos + up, Color::srgb_u8(0, 0, 255)); gizmos.ray(pos, pos + up, Color::srgb_u8(0, 0, 255));
//gizmos.ray(pos, pos + right, Color::srgb_u8(0, 255, 0)); gizmos.ray(pos, pos + right, Color::srgb_u8(0, 255, 0));
} }
} }
pub fn rotate_camera( pub fn rotate_camera(
mut query: Query<&mut Transform, With<Camera>>, mut query: Query<&mut Transform, With<Camera>>,
mut paused: ResMut<Paused>,
keys: Res<ButtonInput<KeyCode>>, keys: Res<ButtonInput<KeyCode>>,
lookat: Res<LookAt>, lookat: Res<LookAt>,
) { ) {
@ -219,6 +231,11 @@ pub fn rotate_camera(
let forward = xform.forward() * 0.7; let forward = xform.forward() * 0.7;
let right = xform.right().as_vec3(); let right = xform.right().as_vec3();
if keys.just_pressed(KeyCode::Space) {
let pause = **paused;
**paused = !pause;
}
if keys.pressed(KeyCode::ArrowRight) { if keys.pressed(KeyCode::ArrowRight) {
xform.translation += right; xform.translation += right;
} }

View file

@ -2,7 +2,6 @@ use std::time::Duration;
use audubon::*; use audubon::*;
use bevy::{ use bevy::{
color::palettes::css::BLACK,
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
prelude::*, prelude::*,
}; };
@ -27,9 +26,10 @@ fn main() {
brightness: 1.0, brightness: 1.0,
}) })
.insert_resource(LookAt::default()) .insert_resource(LookAt::default())
.insert_resource(Paused::default())
.add_systems(Startup, (setup, setup_ambient_light)) .add_systems(Startup, (setup, setup_ambient_light))
//.add_systems(Update, update_gizmos) //.add_systems(Update, update_gizmos)
.add_systems(Update, (update_pos, update_buddies, update_vel).chain()) .add_systems(Update, (update_pos, update_buddies, update_vel))
.add_systems(Update, (rotate_camera, close_on_esc)) .add_systems(Update, (rotate_camera, close_on_esc))
.run(); .run();
} }