Chaos Vehicles: bone-based aerofoil offset mixes centimetres and metres, causing ~100× force arms

Summary

In UE 5.8.1, Chaos Vehicles appears to mix units when a native aerofoil is attached to a skeletal bone.

LocateBoneOffset() returns the bone-derived root-local offset in Unreal centimetres, but FillAerofoilSetup assigns that value to Chaos::FAerofoilConfig::Offset, which is interpreted as metres. The normal downstream metres-to-centimetres conversion then scales the bone contribution again.

This produces force-application arms approximately 100× too large, causing extreme aerodynamic torque, acceleration, angular velocity and G-load.

Converting only the bone-derived contribution from centimetres to metres fixes the issue while preserving manually authored aerofoil offsets in metres.

What Type of Bug are you experiencing?

Simulation

Steps to Reproduce

  1. Open a UE 5.8.1 project with the experimental Chaos Vehicles plugin enabled.

  2. Create or use a skeletal-mesh Chaos vehicle with a bone approximately 300 cm from the vehicle/root-body origin.

  3. Add a native Chaos Vehicles aerofoil configuration and set its BoneName to that bone.

  4. Set the aerofoil’s manually authored Offset to FVector::ZeroVector so the bone-derived contribution can be inspected independently.

  5. Set a breakpoint or diagnostic log immediately after PAerofoilConfig.Offset is assigned in FillAerofoilSetup, in:

    Engine/Plugins/Experimental/ChaosVehiclesPlugin/
    Source/ChaosVehicles/Private/
    ChaosVehicleMovementComponent.cpp

  6. Run the vehicle and inspect the resulting low-level aerofoil Offset.

  7. Observe that a bone translation of approximately 300 cm is stored numerically as approximately 300 in the metre-valued low-level offset, rather than approximately 3.0 m.

  8. Continue to the aerofoil force-application path or inspect the resulting world force point. The normal downstream metres-to-centimetres conversion places the force point approximately 30,000 cm from the root instead of approximately 300 cm.

  9. Apply the suggested unit-boundary correction included in Additional Notes and repeat the test.

  10. Confirm that the low-level offset is now approximately 3.0 m and the resulting force-application point is approximately 300 cm from the root.

Expected Result

A bone-derived translation expressed in Unreal centimetres should be converted to metres exactly once before being stored in Chaos::FAerofoilConfig::Offset.

For example, a bone located 300 cm from the vehicle root should contribute approximately 3.0 m to the low-level aerofoil offset.

Any manually authored FVehicleAerofoilConfig::Offset should remain expressed in metres.

The existing downstream metres-to-centimetres conversion should then place the aerodynamic force at the correct Unreal world-space position.

Observed Result

The centimetre-valued bone translation is stored numerically in a metre-valued field without conversion.

For example, a bone translation of approximately 300 cm becomes approximately 300 m in Chaos::FAerofoilConfig::Offset. The later normal metres-to-centimetres conversion then produces an approximately 30,000 cm force arm.

In our seven-aerofoil aircraft test, four bone-mounted wing force arms that should have been approximately 3.94–5.72 m were approximately 392–570 m under the stock implementation.

This produced extreme aerodynamic torque, angular velocity, acceleration and G-load. Aerofoils located at the root were unaffected.

Affects Versions

5.8

Platform(s)

Windows

Additional Notes

Verified version:

Unreal Engine 5.8.1
CL 56057345
Windows

Relevant source:

Engine/Plugins/Experimental/ChaosVehiclesPlugin/
Source/ChaosVehicles/Private/
ChaosVehicleMovementComponent.cpp

Function:

FillAerofoilSetup

The current assignment is effectively:

PAerofoilConfig.Offset =
MovementComponent.LocateBoneOffset(
this->BoneName,
this->Offset);

The unit chain appears to be:

  • FVehicleAerofoilConfig::Offset: vehicle/root-body local metres
  • LocateBoneOffset(): vehicle/root-body local Unreal centimetres
  • Chaos::FAerofoilConfig::Offset: metres
  • ApplyAerofoilForces(): later converts the metre offset to Unreal centimetres

This mixes the manually authored metre offset and the centimetre-valued bone position before placing the result into a metre-valued field.

Suggested correction:

PAerofoilConfig.Offset =
this->Offset
+ Chaos::CmToM(
MovementComponent.LocateBoneOffset(
this->BoneName,
FVector::ZeroVector));

This preserves the manually authored offset in metres and converts only the bone-derived contribution from centimetres to metres.

The existing later metres-to-centimetres conversion should remain. That conversion is correct; the mismatch occurs earlier when the centimetre-valued bone position enters the metre-valued low-level field.

Matched aircraft validation:

Stock UE 5.8.1:

  • Four bone-mounted wing force arms: approximately 392–570 m
  • Peak speed: approximately 1,668,791 cm/s
  • Peak angular rate: approximately 62.83 rad/s
  • Peak raw G: approximately 31,649 G

With the unit-boundary correction:

  • Corresponding force arms: approximately 3.94–5.72 m
  • Peak speed: approximately 19,529 cm/s
  • Peak angular rate: approximately 0.120 rad/s
  • Peak raw G: approximately 1.0 G

The correction restored all seven aerofoil locations and removed the runaway without changing aircraft mass, inertia, aerofoil areas, aerodynamic coefficients, control mappings, FCC behaviour or other flight tuning.

I have verified this against UE 5.8.1. I have not yet source-checked the implementation in UE 5.8.2.