mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-17 00:13:17 +00:00
Mitigate BVH retargeting jitter (#29)
The initial BVH retargeting solution produced very jittery results. Much of that jitter was eliminated by using linear interpolation between frames instead of immediate stepped transitions, but some jittering still remained, particularly noticeable in the finger motions. This PR largely fixes remaining jitter issues by making a few changes: #### Frame-time quantization Previously, we had been using the `BvhAnim::timer` field incorrectly, by manually resetting it after `Timer::just_finished` returned `true`, and returning `0.0` as the interpolation parameter for that frame. This resulted in a herky-jerky animation due to misalignment between the BVH animation's frame time and the actual application refresh rate, meaning we would lose fractions of a frame every time the timer elapsed and the frame was incremented. This PR addresses that by never calling `Timer::reset` and always using `Timer::percent` for the interpolation parameter. #### Matrix instability This PR refactors the retargeting system to operate on `Affine3A` matrices instead of `Mat4`s. `Affine3A` represents a SIMD-optimized 3x3 matrix + a translation vector, so using it provides a small performance boost in addition to being slightly more numerically stable. Additionally, we now periodically re-orthonormalize the 3x3 matrices in-between operations to mitigate drifting due to the accumulation of floating-point errors.
This commit is contained in:
@@ -9,6 +9,7 @@ where
|
||||
{
|
||||
fn decompose_scale(&self) -> Self;
|
||||
fn decompose_scale_rotation(&self) -> (Self, Self);
|
||||
fn orthonormalize(&self) -> Self;
|
||||
}
|
||||
|
||||
pub trait VecExtras
|
||||
@@ -49,6 +50,23 @@ impl MatrixExtras for Mat3A {
|
||||
|
||||
(scale_mat, rotation)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn orthonormalize(&self) -> Self {
|
||||
let x_axis = self.x_axis.normalize();
|
||||
|
||||
let mut y_axis = self.y_axis;
|
||||
y_axis -= y_axis.dot(x_axis) / x_axis.dot(x_axis) * x_axis;
|
||||
y_axis = y_axis.normalize();
|
||||
|
||||
let z_axis = x_axis.cross(y_axis);
|
||||
|
||||
Self {
|
||||
x_axis,
|
||||
y_axis,
|
||||
z_axis,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MatrixExtras for Mat3 {
|
||||
@@ -62,6 +80,11 @@ impl MatrixExtras for Mat3 {
|
||||
let (scale, rotation) = Mat3A::from(*self).decompose_scale_rotation();
|
||||
(scale.into(), rotation.into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn orthonormalize(&self) -> Self {
|
||||
Mat3A::from(*self).orthonormalize().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl VecExtras for Vec3A {
|
||||
|
||||
Reference in New Issue
Block a user