Last active
February 19, 2025 10:59
-
-
Save RJ/74e598b84dd81feb40f72407dee4ad79 to your computer and use it in GitHub Desktop.
half-baked avian quantization plugin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use crate::prelude::*; | |
use bevy::{ | |
ecs::{intern::Interned, schedule::ScheduleLabel}, | |
prelude::*, | |
}; | |
use crate::{prepare::PrepareSet, sync::SyncSet}; | |
/// Quantizes all the things | |
pub struct QuantizationPlugin { | |
schedule: Interned<dyn ScheduleLabel>, | |
} | |
impl QuantizationPlugin { | |
/// Creates a [`QuantizationPlugin`] using the given schedule | |
pub fn new(schedule: impl ScheduleLabel) -> Self { | |
Self { | |
schedule: schedule.intern(), | |
} | |
} | |
} | |
impl Plugin for QuantizationPlugin { | |
fn build(&self, app: &mut App) { | |
app.add_systems( | |
self.schedule, | |
( | |
q_position, | |
q_linear_velocity, | |
q_rotation, | |
q_angular_velocity, | |
) | |
.in_set(PrepareSet::First), | |
); | |
app.add_systems( | |
self.schedule, | |
( | |
q_position, | |
q_linear_velocity, | |
q_rotation, | |
q_angular_velocity, | |
) | |
.in_set(SyncSet::First), | |
); | |
} | |
} | |
fn q_position(mut q: Query<&mut Position>) { | |
for mut v in q.iter_mut() { | |
v.0.quantize(); | |
} | |
} | |
fn q_rotation(mut q: Query<&mut Rotation>) { | |
for mut v in q.iter_mut() { | |
#[cfg(feature = "2d")] | |
{ | |
v.cos.quantize(); | |
v.sin.quantize(); | |
// normalize better here? | |
v.cos = v.cos.clamp(-1.0, 1.0); | |
v.sin = v.sin.clamp(-1.0, 1.0); | |
} | |
#[cfg(feature = "3d")] | |
{ | |
v.0.quantize(); | |
} | |
} | |
} | |
fn q_linear_velocity(mut q: Query<&mut LinearVelocity>) { | |
for mut v in q.iter_mut() { | |
v.0.quantize(); | |
} | |
} | |
fn q_angular_velocity(mut q: Query<&mut AngularVelocity>) { | |
for mut v in q.iter_mut() { | |
let before = v.0; | |
v.0.quantize(); | |
println!("a_angvel, before: {:?}, after: {:?}", before, v.0); | |
} | |
} | |
// -- | |
/// Scale factor for quantization | |
/// 1/8192 ≈ 0.00122 | |
pub const QUANTIZE_SCALE: f32 = 8192.0; | |
/// Trait extension for quantizing `f32` | |
pub trait QuantizableF32 { | |
fn quantize(&mut self); | |
} | |
impl QuantizableF32 for f32 { | |
fn quantize(&mut self) { | |
*self = ((*self * QUANTIZE_SCALE).round() as i32) as f32 / QUANTIZE_SCALE; | |
} | |
} | |
/// Trait extension for quantizing `Vec2` | |
pub trait QuantizableVec2 { | |
fn quantize(&mut self); | |
} | |
impl QuantizableVec2 for Vec2 { | |
fn quantize(&mut self) { | |
self.x.quantize(); | |
self.y.quantize(); | |
} | |
} | |
pub trait QuantizableVec3 { | |
fn quantize(&mut self); | |
} | |
impl QuantizableVec3 for Vec3 { | |
fn quantize(&mut self) { | |
self.x.quantize(); | |
self.y.quantize(); | |
self.z.quantize(); | |
} | |
} | |
/// Trait extension for quantizing `Quat` | |
pub trait QuantizableQuat { | |
fn quantize(&mut self); | |
} | |
impl QuantizableQuat for Quat { | |
fn quantize(&mut self) { | |
self.x.quantize(); | |
self.y.quantize(); | |
self.z.quantize(); | |
self.w.quantize(); | |
*self = self.normalize(); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
i used 8192 because my physics values are up to 10k magnitude.
with a
QUANTIZE_SCALE = 4096.0
, the smallest step is 1/4096 (0.000244), andf32
can accurately distinguish steps of this size at values up to around 5000.0.if your physics values are in the -1000 to 1000 range you could use a scale of 1000 (0.0001 accuracy).
depends on the game world. you could also think in meters/millimeters and set the quantization so you know exactly the minimum number of physics units you can represent (ie, 1mm of accuracy is enough).
(f32 having a 23 bit mantissa so the smallest step is ~
quantize_scale/(2^23)
)