30
30
31
31
#include " vehicle_body_3d.h"
32
32
33
+ #include " core/config/engine.h"
34
+
33
35
#define ROLLING_INFLUENCE_FIX
34
36
35
37
class btVehicleJacobianEntry {
@@ -78,6 +80,40 @@ class btVehicleJacobianEntry {
78
80
}
79
81
};
80
82
83
+ void VehicleWheel3D::FTIData::update_world_xform (Transform3D &r_xform, real_t p_interpolation_fraction) {
84
+ // Note that when unset (during the first few frames before a physics tick)
85
+ // the xform will be whatever it was loaded as.
86
+ if (!unset) {
87
+ real_t f = p_interpolation_fraction;
88
+
89
+ WheelXform i;
90
+ i.up = prev.up .lerp (curr.up , f);
91
+ i.up .normalize ();
92
+ i.right = prev.right .lerp (curr.right , f);
93
+ i.right .normalize ();
94
+
95
+ Vector3 fwd = i.up .cross (i.right );
96
+ fwd.normalize ();
97
+
98
+ i.origin = prev.origin .lerp (curr.origin , f);
99
+ i.steering = Math::lerp (prev.steering , curr.steering , f);
100
+
101
+ real_t rotation = Math::lerp (curr_rotation - curr_rotation_delta, curr_rotation, f);
102
+
103
+ Basis steeringMat (i.up , i.steering );
104
+
105
+ Basis rotatingMat (i.right , rotation);
106
+
107
+ Basis basis2 (
108
+ i.right [0 ], i.up [0 ], fwd[0 ],
109
+ i.right [1 ], i.up [1 ], fwd[1 ],
110
+ i.right [2 ], i.up [2 ], fwd[2 ]);
111
+
112
+ r_xform.set_basis (steeringMat * rotatingMat * basis2);
113
+ r_xform.set_origin (i.origin );
114
+ }
115
+ }
116
+
81
117
void VehicleWheel3D::_notification (int p_what) {
82
118
switch (p_what) {
83
119
case NOTIFICATION_ENTER_TREE: {
@@ -381,6 +417,28 @@ void VehicleBody3D::_update_wheel(int p_idx, PhysicsDirectBodyState3D *s) {
381
417
Vector3 fwd = up.cross (right);
382
418
fwd = fwd.normalized ();
383
419
420
+ VehicleWheel3D::FTIData &id = wheel.fti_data ;
421
+
422
+ Vector3 origin = wheel.m_raycastInfo .m_hardPointWS + wheel.m_raycastInfo .m_wheelDirectionWS * wheel.m_raycastInfo .m_suspensionLength ;
423
+
424
+ if (is_physics_interpolated_and_enabled ()) {
425
+ id.curr .up = up;
426
+ id.curr .right = right;
427
+ id.curr .steering = wheel.m_steering ;
428
+ id.curr .origin = origin;
429
+
430
+ // Pump the xform the first update to the wheel,
431
+ // otherwise the world xform prev will be NULL.
432
+ if (id.unset || id.reset_queued ) {
433
+ id.unset = false ;
434
+ id.reset_queued = false ;
435
+ id.pump ();
436
+ }
437
+
438
+ // The physics etc relies on the rest of this being correct, even with FTI,
439
+ // so we can't pre-maturely return here.
440
+ }
441
+
384
442
Basis steeringMat (up, wheel.m_steering );
385
443
386
444
Basis rotatingMat (right, wheel.m_rotation );
@@ -392,8 +450,7 @@ void VehicleBody3D::_update_wheel(int p_idx, PhysicsDirectBodyState3D *s) {
392
450
393
451
wheel.m_worldTransform .set_basis (steeringMat * rotatingMat * basis2);
394
452
// wheel.m_worldTransform.set_basis(basis2 * (steeringMat * rotatingMat));
395
- wheel.m_worldTransform .set_origin (
396
- wheel.m_raycastInfo .m_hardPointWS + wheel.m_raycastInfo .m_wheelDirectionWS * wheel.m_raycastInfo .m_suspensionLength );
453
+ wheel.m_worldTransform .set_origin (origin);
397
454
}
398
455
399
456
real_t VehicleBody3D::_ray_cast (int p_idx, PhysicsDirectBodyState3D *s) {
@@ -817,6 +874,58 @@ void VehicleBody3D::_update_friction(PhysicsDirectBodyState3D *s) {
817
874
}
818
875
}
819
876
877
+ void VehicleBody3D::_physics_interpolated_changed () {
878
+ _update_process_mode ();
879
+ RigidBody3D::_physics_interpolated_changed ();
880
+ }
881
+
882
+ void VehicleBody3D::fti_pump_xform () {
883
+ for (int i = 0 ; i < wheels.size (); i++) {
884
+ VehicleWheel3D &w = *wheels[i];
885
+ w.fti_data .pump ();
886
+ }
887
+
888
+ RigidBody3D::fti_pump_xform ();
889
+ }
890
+
891
+ void VehicleBody3D::_update_process_mode () {
892
+ set_process_internal (is_physics_interpolated_and_enabled ());
893
+ }
894
+
895
+ void VehicleBody3D::_notification (int p_what) {
896
+ switch (p_what) {
897
+ case NOTIFICATION_ENTER_TREE: {
898
+ _update_process_mode ();
899
+ } break ;
900
+ case NOTIFICATION_INTERNAL_PROCESS: {
901
+ #ifdef DEV_ENABLED
902
+ if (!is_physics_interpolated_and_enabled ()) {
903
+ WARN_PRINT_ONCE (" VehicleBody NOTIFICATION_INTERNAL_PROCESS with physics interpolation OFF. (benign)" );
904
+ }
905
+ #endif
906
+ real_t f = Engine::get_singleton ()->get_physics_interpolation_fraction ();
907
+
908
+ Transform3D xform;
909
+ Transform3D inv_vehicle_xform = get_global_transform_interpolated ().affine_inverse ();
910
+
911
+ for (int i = 0 ; i < wheels.size (); i++) {
912
+ VehicleWheel3D &w = *wheels[i];
913
+ w.fti_data .update_world_xform (xform, f);
914
+ w.set_transform (inv_vehicle_xform * xform);
915
+ }
916
+ } break ;
917
+ case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: {
918
+ _update_process_mode ();
919
+ for (int i = 0 ; i < wheels.size (); i++) {
920
+ VehicleWheel3D &w = *wheels[i];
921
+ w.fti_data .reset_queued = true ;
922
+ }
923
+ } break ;
924
+ default :
925
+ break ;
926
+ }
927
+ }
928
+
820
929
void VehicleBody3D::_body_state_changed (PhysicsDirectBodyState3D *p_state) {
821
930
RigidBody3D::_body_state_changed (p_state);
822
931
@@ -826,9 +935,14 @@ void VehicleBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
826
935
_update_wheel (i, p_state);
827
936
}
828
937
938
+ bool use_fti = is_physics_interpolated_and_enabled ();
939
+
829
940
for (int i = 0 ; i < wheels.size (); i++) {
830
941
_ray_cast (i, p_state);
831
- wheels[i]->set_transform (p_state->get_transform ().inverse () * wheels[i]->m_worldTransform );
942
+ if (!use_fti) {
943
+ // TODO: can this path also just use world space directly instead of inverse parent space?
944
+ wheels[i]->set_transform (p_state->get_transform ().inverse () * wheels[i]->m_worldTransform );
945
+ }
832
946
}
833
947
834
948
_update_suspension (p_state);
@@ -880,6 +994,9 @@ void VehicleBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
880
994
}
881
995
882
996
wheel.m_rotation += wheel.m_deltaRotation ;
997
+ if (use_fti) {
998
+ wheel.fti_data .rotate (wheel.m_deltaRotation );
999
+ }
883
1000
wheel.m_rpm = ((wheel.m_deltaRotation / step) * 60 ) / Math::TAU;
884
1001
885
1002
wheel.m_deltaRotation *= real_t (0.99 ); // damping of rotation when not in contact
0 commit comments