diff --git a/Source/Engine/Animations/InverseKinematics.cpp b/Source/Engine/Animations/InverseKinematics.cpp index 06523be81..c5db48320 100644 --- a/Source/Engine/Animations/InverseKinematics.cpp +++ b/Source/Engine/Animations/InverseKinematics.cpp @@ -10,7 +10,6 @@ void InverseKinematics::SolveAimIK(const Transform& node, const Vector3& target, Quaternion::FindBetween(fromNode, toTarget, outNodeCorrection); } - void InverseKinematics::SolveTwoBoneIK(Transform& rootTransform, Transform& midJointTransform, Transform& endEffectorTransform, const Vector3& targetPosition, const Vector3& poleVector, bool allowStretching, float maxStretchScale) { // Calculate limb segment lengths @@ -82,17 +81,20 @@ void InverseKinematics::SolveTwoBoneIK(Transform& rootTransform, Transform& midJ Vector3 newEndEffectorPos = targetPosition; Vector3 newMidJointPos = midJointPos; - if (toTargetLength >= totalLimbLength) { + if (toTargetLength >= totalLimbLength) + { // Target is beyond the reach of the limb Vector3 rootToEnd = (targetPosition - rootTransform.Translation).GetNormalized(); // Calculate the slight offset towards the pole vector Vector3 rootToPole = (poleVector - rootTransform.Translation).GetNormalized(); Vector3 slightBendDirection = Vector3::Cross(rootToEnd, rootToPole); - if (slightBendDirection.LengthSquared() < ZeroTolerance * ZeroTolerance) { + if (slightBendDirection.LengthSquared() < ZeroTolerance * ZeroTolerance) + { slightBendDirection = Vector3::Up; } - else { + else + { slightBendDirection.Normalize(); } @@ -140,7 +142,6 @@ void InverseKinematics::SolveTwoBoneIK(Transform& rootTransform, Transform& midJ rootTransform.Orientation = newRootJointOrientation; } - // Update mid joint orientation to point Y-axis towards the end effector and Z-axis perpendicular to the IK plane { // Vector from mid joint to end effector (local Y-axis direction after rotation) @@ -150,7 +151,6 @@ void InverseKinematics::SolveTwoBoneIK(Transform& rootTransform, Transform& midJ Vector3 rootToMid = (newMidJointPos - rootTransform.Translation).GetNormalized(); Vector3 planeNormal = Vector3::Cross(rootToMid, midToEnd).GetNormalized(); - // Vector from mid joint to end effector (local Y-axis direction) Vector3 localY = (newEndEffectorPos - newMidJointPos).GetNormalized(); @@ -163,7 +163,6 @@ void InverseKinematics::SolveTwoBoneIK(Transform& rootTransform, Transform& midJ // Correct the local Z-axis direction based on the cross product of X and Y to ensure orthogonality localZ = Vector3::Cross(localX, localY).GetNormalized(); - // Construct a rotation from the orthogonal basis vectors // The axes are used differently here than a standard LookRotation to align Z towards the end and Y perpendicular Quaternion newMidJointOrientation = Quaternion::LookRotation(localZ, localY); // Assuming FromLookRotation creates a rotation with the first vector as forward and the second as up diff --git a/Source/Engine/Engine/Engine.cpp b/Source/Engine/Engine/Engine.cpp index c9d4bc5ae..0a500eaf4 100644 --- a/Source/Engine/Engine/Engine.cpp +++ b/Source/Engine/Engine/Engine.cpp @@ -192,8 +192,11 @@ int32 Engine::Main(const Char* cmdLine) OnUnpause(); } + // Use the same time for all ticks to improve synchronization + const double time = Platform::GetTimeSeconds(); + // Update game logic - if (Time::OnBeginUpdate()) + if (Time::OnBeginUpdate(time)) { OnUpdate(); OnLateUpdate(); @@ -201,7 +204,7 @@ int32 Engine::Main(const Char* cmdLine) } // Start physics simulation - if (Time::OnBeginPhysics()) + if (Time::OnBeginPhysics(time)) { OnFixedUpdate(); OnLateFixedUpdate(); @@ -209,7 +212,7 @@ int32 Engine::Main(const Char* cmdLine) } // Draw frame - if (Time::OnBeginDraw()) + if (Time::OnBeginDraw(time)) { OnDraw(); Time::OnEndDraw(); diff --git a/Source/Engine/Engine/Time.cpp b/Source/Engine/Engine/Time.cpp index 7f4571b32..43ac4f9b5 100644 --- a/Source/Engine/Engine/Time.cpp +++ b/Source/Engine/Engine/Time.cpp @@ -72,10 +72,9 @@ void Time::TickData::OnReset(float targetFps, double currentTime) LastEnd = currentTime; } -bool Time::TickData::OnTickBegin(float targetFps, float maxDeltaTime) +bool Time::TickData::OnTickBegin(double time, float targetFps, float maxDeltaTime) { // Check if can perform a tick - const double time = Platform::GetTimeSeconds(); double deltaTime; if (FixedDeltaTimeEnable) { @@ -126,10 +125,9 @@ void Time::TickData::Advance(double time, double deltaTime) TicksCount++; } -bool Time::FixedStepTickData::OnTickBegin(float targetFps, float maxDeltaTime) +bool Time::FixedStepTickData::OnTickBegin(double time, float targetFps, float maxDeltaTime) { // Check if can perform a tick - double time = Platform::GetTimeSeconds(); double deltaTime, minDeltaTime; if (FixedDeltaTimeEnable) { @@ -249,9 +247,9 @@ void Time::Synchronize() Draw.Synchronize(DrawFPS, time); } -bool Time::OnBeginUpdate() +bool Time::OnBeginUpdate(double time) { - if (Update.OnTickBegin(UpdateFPS, MaxUpdateDeltaTime)) + if (Update.OnTickBegin(time, UpdateFPS, MaxUpdateDeltaTime)) { Current = &Update; return true; @@ -259,9 +257,9 @@ bool Time::OnBeginUpdate() return false; } -bool Time::OnBeginPhysics() +bool Time::OnBeginPhysics(double time) { - if (Physics.OnTickBegin(PhysicsFPS, _physicsMaxDeltaTime)) + if (Physics.OnTickBegin(time, PhysicsFPS, _physicsMaxDeltaTime)) { Current = &Physics; return true; @@ -269,9 +267,9 @@ bool Time::OnBeginPhysics() return false; } -bool Time::OnBeginDraw() +bool Time::OnBeginDraw(double time) { - if (Draw.OnTickBegin(DrawFPS, 1.0f)) + if (Draw.OnTickBegin(time, DrawFPS, 1.0f)) { Current = &Draw; return true; diff --git a/Source/Engine/Engine/Time.h b/Source/Engine/Engine/Time.h index 4bb269cb9..ff81fb93e 100644 --- a/Source/Engine/Engine/Time.h +++ b/Source/Engine/Engine/Time.h @@ -12,12 +12,12 @@ /// API_CLASS(Static) class FLAXENGINE_API Time { -DECLARE_SCRIPTING_TYPE_NO_SPAWN(Time); + DECLARE_SCRIPTING_TYPE_NO_SPAWN(Time); friend class Engine; friend class TimeService; friend class PhysicsSettings; -public: +public: /// /// Engine subsystem updating data. /// Used to invoke game logic updates, physics updates and rendering with possibly different frequencies. @@ -25,7 +25,6 @@ public: class FLAXENGINE_API TickData { public: - virtual ~TickData() = default; /// @@ -75,14 +74,12 @@ public: TimeSpan UnscaledTime; public: - - virtual void OnBeforeRun(float targetFps, double currentTime); + virtual void Synchronize(float targetFps, double currentTime); virtual void OnReset(float targetFps, double currentTime); - virtual bool OnTickBegin(float targetFps, float maxDeltaTime); + virtual bool OnTickBegin(double time, float targetFps, float maxDeltaTime); virtual void OnTickEnd(); protected: - void Advance(double time, double deltaTime); }; @@ -92,25 +89,21 @@ public: class FixedStepTickData : public TickData { public: - /// /// The last few ticks delta times. Used to check if can use fixed steps or whenever is running slowly so should use normal stepping. /// SamplesBuffer Samples; public: - // [TickData] - bool OnTickBegin(float targetFps, float maxDeltaTime) override; + bool OnTickBegin(double time, float targetFps, float maxDeltaTime) override; }; private: - static bool _gamePaused; static float _physicsMaxDeltaTime; public: - /// /// The time at which the game started (UTC local). /// @@ -140,7 +133,6 @@ public: API_FIELD() static float TimeScale; public: - /// /// The game logic updating data. /// @@ -162,7 +154,6 @@ public: static TickData* Current; public: - /// /// Gets the current tick data (safety so returns Update tick data if no active). /// @@ -233,9 +224,9 @@ public: private: // Methods used by the Engine class - static bool OnBeginUpdate(); - static bool OnBeginPhysics(); - static bool OnBeginDraw(); + static bool OnBeginUpdate(double time); + static bool OnBeginPhysics(double time); + static bool OnBeginDraw(double time); static void OnEndUpdate(); static void OnEndPhysics();