Fix wipeout bail teleport NaN physics abort.

Reset biped controller on checkpoint teleport and fall back to identity when skeleton root orthonormalization sees a degenerate axis, preventing poisoned COM frames and deck torque before the shared solve.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Ethanw05andCursor committed 2026-09-12 20:16:39 -06:00
1 parent e2b85b6489
commit c87373dd6a
2 files changed
+25 -2

No files matched your search

+22 -2
View File
@@ -123,8 +123,16 @@ pub(crate) fn orthonormalize(source: AnimationPartTransform) -> AnimationPartTra
*value -= result[prior][lane] * projection;
}
}
let reciprocal = inverse_length_squared(dot3(vector, vector), 2);
result[axis] = vector.map(|v| v * reciprocal);
let squared = dot3(vector, vector);
if squared <= f32::from_bits(0x3586_37bd) {
// Degenerate axes appear after wipeout bail teleports when heading
// initialization and ragdoll frames disagree. NaN here poisons COM
// frames and deck torque before the shared solve.
result[axis] = IDENTITY[axis];
} else {
let reciprocal = inverse_length_squared(squared, 2);
result[axis] = vector.map(|v| v * reciprocal);
}
}
result
}
@@ -171,4 +179,16 @@ mod tests {
}
}
}
#[test]
fn degenerate_axis_falls_back_to_identity() {
let mut source = IDENTITY;
source[0] = [0.; 4];
source[1] = [0.; 4];
source[2] = [0.; 4];
let result = orthonormalize(source);
for axis in 0..3 {
assert_eq!(result[axis], IDENTITY[axis]);
}
}
}
+3
View File
@@ -86,6 +86,9 @@ pub(super) fn advance(
super::offboard_root_trace::trace(tick, "teleport", skater);
//82DB93B0..CC: complete pending queries and clear contact history.
skater.offboard_contact.reset_history();
// Biped cadence survives ordinary Ground reset, but a checkpoint teleport
// must not retain an off-board placement from a prior wipeout recovery.
skater.biped_ground.controller.reset();
skater.player_state.reset_for_teleport();
skater.centre_of_mass_filter.reset();
skater.animation_feedback.reset();