From 911a7059ae17abff672839903a9f971ea07bcdf0 Mon Sep 17 00:00:00 2001 From: Zwitschi Date: Tue, 10 Nov 2026 19:45:17 +0100 Subject: [PATCH] docs(vehicle): revert the axis fix; the reverse is in the Chaos solver The axis_forward:X / Blender-Z axle fix changed the reference pose but not the drive (-2737 cm/s), and axis_forward:X also alters the shared character preset. Revert it. The Chaos solver drives the wheel about the vehicle's Y (not the bone), and the drive force is positive yet the car moves backward - the inversion is in the engine torque / drive-force sign. Next: GetEngineTorque() sign or a SetupVehicle override. --- MEMORY.md | 12 ++++++++++++ Tools/blender/fbx_export_preset.py | 1 - Tools/blender/vehicle_build.py | 6 ++---- Tools/unreal/ue_vehicle_import.py | 5 ----- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/MEMORY.md b/MEMORY.md index 27e56f9..9278ec7 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -1105,3 +1105,15 @@ Historical task context from 2026-11-09/10; later vehicle findings above may sup velocity axis) or the engine torque sign, not the bone authoring. The horizontal-axle fix is kept (it is correct even if insufficient): `axis_forward: X` in the character preset and a Blender-Z wheel tail (`r - copysign(0.25, y)`) so the axle lands on Unreal Y. + +## 2026-11-10 — Vehicle reverse is in the Chaos solver, not the assets (revert the axis fix) + +- Reverted the `axis_forward: X` / Blender-Z axle fix (`ecdd820`): the reference pose changed + but `-drivetest` still read −2737 cm/s, and `axis_forward: X` lives in the shared character + preset, so it would also alter every character export. +- Traced the Chaos solver: the wheel's local frame is `GroundXVector = CrossProduct(VehicleRightAxis, + GroundZVector)` and the drive force is `FinalLongitudinalForce = DriveTorque / Re`, applied forward — + yet the car moves backward. The wheel spins about the **vehicle's** Y, not the bone's, so the bone + authoring is irrelevant. The inversion is in the **engine-torque / drive-force sign** (`FSimpleWheel`), + not the assets. Next: check `GetEngineTorque()` sign, or override `SetupVehicle`/`ProcessMechanicalSimulation` + in `UGigLineVehicleMovement` to negate the drive torque. diff --git a/Tools/blender/fbx_export_preset.py b/Tools/blender/fbx_export_preset.py index 6cc201c..fc2f459 100644 --- a/Tools/blender/fbx_export_preset.py +++ b/Tools/blender/fbx_export_preset.py @@ -60,7 +60,6 @@ _METRIC = { _CHARACTER = dict( _METRIC, object_types={"ARMATURE", "MESH"}, - axis_forward="X", add_leaf_bones=False, path_mode="COPY", embed_textures=False, diff --git a/Tools/blender/vehicle_build.py b/Tools/blender/vehicle_build.py index aa2493c..5a54388 100644 --- a/Tools/blender/vehicle_build.py +++ b/Tools/blender/vehicle_build.py @@ -199,10 +199,8 @@ def build_skeletal(joined, wheels, out_fbx, exp_dir): for name, (x, y) in wheel_positions.items(): bone = edit_bones.new(name) bone.head = (x, y, r) - # Point the bone along the axle in BLENDER Z: the Unreal FBX import maps (x,y,z)-> - # (x,-z,-y), so a tail along Z lands on Unreal Y (horizontal axle). Opposite sides - # get opposite signs (left down, right up) so the axles point outward. - bone.tail = (x, y, r - math.copysign(0.25, y)) + # Point the bone along the axle: the wheel spins about its own Y. + bone.tail = (x, y - math.copysign(0.25, y), r) bone.parent = root bpy.ops.object.mode_set(mode="OBJECT") diff --git a/Tools/unreal/ue_vehicle_import.py b/Tools/unreal/ue_vehicle_import.py index 582dd9c..2ddfe1c 100644 --- a/Tools/unreal/ue_vehicle_import.py +++ b/Tools/unreal/ue_vehicle_import.py @@ -119,11 +119,6 @@ def main(): ui.import_animations = False ui.import_materials = True ui.skeletal_mesh_import_data.import_uniform_scale = 1.0 - # The FBX is already authored in the Unreal frame (nose +X, axle along Y); the - # importer's default axis conversion otherwise rolls the armature 90 deg about X and - # the wheel axles land on Z, which drives the Chaos vehicle backward. - ui.skeletal_mesh_import_data.import_rotation = unreal.Rotator(0.0, 0.0, 0.0) - ui.skeletal_mesh_import_data.import_translation = unreal.Vector(0.0, 0.0, 0.0) task.options = ui unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task]) skel = unreal.EditorAssetLibrary.load_asset(f"{DEST}/SK_Vehicle_Sedan")