Skip to content

Commit 9e193f0

Browse files
committed
nif: turn volume emitters' velocity into the system's space
A box, cylinder or sphere emitter's new particle has its velocity taken into the system's space by the rotation of the emitter-to-system transform, without its scale, as its position is. Only the position was taken there, so a particle left along the emitter's own axis however its object was turned: Drift City's crash effects, whose emitters are turned to face sideways, sent everything straight up.
1 parent 04175f2 commit 9e193f0

1 file changed

Lines changed: 31 additions & 0 deletions

File tree

‎crates/nif/src/psys.rs‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,9 @@ fn place(
810810
particle: &mut Particle,
811811
rng: &mut Rng,
812812
) {
813+
// A volume emitter's velocity is turned into the system's space along with its position; a
814+
// mesh emitter aims by the surface instead, below.
815+
let mut volume = true;
813816
let (local, normal, object) = match blocks.get(index) {
814817
Some(Block::NiPSysBoxEmitter(e)) => (
815818
Vec3::new(
@@ -851,6 +854,7 @@ fn place(
851854
)
852855
}
853856
Some(Block::NiPSysMeshEmitter(e)) => {
857+
volume = false;
854858
// one mesh each in this corpus, but the engine picks at random among them
855859
let count = e.emitter_mesh_refs.len();
856860
if count == 0 {
@@ -879,9 +883,20 @@ fn place(
879883
let speed = Vec3::from(&particle.velocity).length();
880884
let aimed = space.transform_vector3(normal).normalize_or_zero();
881885
particle.velocity = (aimed * speed).into();
886+
} else if volume {
887+
particle.velocity = turned_into(&space, Vec3::from(&particle.velocity)).into();
882888
}
883889
}
884890

891+
/// A velocity taken into a system's space by the turn of the transform that takes an emitter's
892+
/// space there, and not its scale. Left in the emitter's own space, a particle leaves along the
893+
/// emitter's own axis however the object carrying it is turned: an effect exported lying on its
894+
/// side sends everything straight up out of the side it was meant to leave by.
895+
fn turned_into(space: &Mat4, velocity: Vec3) -> Vec3 {
896+
let (_, rotation, _) = space.to_scale_rotation_translation();
897+
rotation * velocity
898+
}
899+
885900
/// A point on a mesh's surface and the direction to leave it by, in the mesh's own space.
886901
///
887902
/// The direction is the **stored vertex normals** of the corners involved, averaged and unitized,
@@ -992,6 +1007,22 @@ mod tests {
9921007
crate::Nif::parse(&mut std::io::Cursor::new(&bytes)).expect("parse")
9931008
}
9941009

1010+
/// A volume emitter's velocity is turned the way the emitter's object is turned against the
1011+
/// system, and keeps its speed however that object is scaled: a crash effect's emitters are
1012+
/// turned to leave sideways, and scaled to a four hundredth.
1013+
#[test]
1014+
fn a_volume_emitters_velocity_is_turned_and_not_scaled() {
1015+
let space = Mat4::from_scale(Vec3::splat(0.0025))
1016+
* Mat4::from_rotation_x(-std::f32::consts::FRAC_PI_2);
1017+
let up = Vec3::new(0.0, 0.0, 5.0);
1018+
let turned = turned_into(&space, up);
1019+
assert!(
1020+
turned.abs_diff_eq(Vec3::new(0.0, 5.0, 0.0), 1e-4),
1021+
"{turned}"
1022+
);
1023+
assert!(turned_into(&Mat4::IDENTITY, up).abs_diff_eq(up, 1e-6));
1024+
}
1025+
9951026
#[test]
9961027
fn a_seek_gives_the_same_answer_twice() {
9971028
let nif = parse("tests/20.nif");

0 commit comments

Comments
 (0)