Update to UE5.5, sadly didn't fix hand movement after attachment
Took 5h to find out Engine was read only
This commit is contained in:
parent
55d567e436
commit
f086787883
40 changed files with 1044 additions and 564 deletions
|
@ -2,9 +2,11 @@
|
||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
"components": [
|
"components": [
|
||||||
"Microsoft.Net.Component.4.6.2.TargetingPack",
|
"Microsoft.Net.Component.4.6.2.TargetingPack",
|
||||||
|
"Microsoft.VisualStudio.Component.Unreal.Workspace",
|
||||||
|
"Microsoft.VisualStudio.Component.VC.14.38.17.8.ATL",
|
||||||
"Microsoft.VisualStudio.Component.VC.14.38.17.8.x86.x64",
|
"Microsoft.VisualStudio.Component.VC.14.38.17.8.x86.x64",
|
||||||
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
|
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
|
||||||
"Microsoft.VisualStudio.Component.Windows10SDK.22621",
|
"Microsoft.VisualStudio.Component.Windows11SDK.22621",
|
||||||
"Microsoft.VisualStudio.Workload.CoreEditor",
|
"Microsoft.VisualStudio.Workload.CoreEditor",
|
||||||
"Microsoft.VisualStudio.Workload.ManagedDesktop",
|
"Microsoft.VisualStudio.Workload.ManagedDesktop",
|
||||||
"Microsoft.VisualStudio.Workload.NativeDesktop",
|
"Microsoft.VisualStudio.Workload.NativeDesktop",
|
||||||
|
|
BIN
VIRTUOS_ExpansionPluginTests/Content/VRE/ExampleMap/MotionControllerMap.umap
(Stored with Git LFS)
BIN
VIRTUOS_ExpansionPluginTests/Content/VRE/ExampleMap/MotionControllerMap.umap
(Stored with Git LFS)
Binary file not shown.
|
@ -1 +1 @@
|
||||||
Subproject commit 006e2b4922eb4f7af0d6df1468a042a98eecf68f
|
Subproject commit 968fe10c9f08859c64ea88768d5216140fc340d9
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"FileVersion": 3,
|
"FileVersion": 3,
|
||||||
"Version": 5.4,
|
"Version": 5.5,
|
||||||
"VersionName": "5.4",
|
"VersionName": "5.5",
|
||||||
"FriendlyName": "OpenXRExpansionPlugin",
|
"FriendlyName": "OpenXRExpansionPlugin",
|
||||||
"Description": "An set of utility functions for OpenXR",
|
"Description": "An set of utility functions for OpenXR",
|
||||||
"Category": "Virtual Reality",
|
"Category": "Virtual Reality",
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "UObject/ObjectMacros.h"
|
#include "UObject/ObjectMacros.h"
|
||||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||||
|
#include "Animation/BoneReference.h"
|
||||||
#include "UObject/Object.h"
|
#include "UObject/Object.h"
|
||||||
#include "Engine/EngineTypes.h"
|
#include "Engine/EngineTypes.h"
|
||||||
|
|
||||||
|
|
|
@ -189,16 +189,16 @@ public:
|
||||||
// Need this as I can't think of another way for an actor component to make sure it isn't on the server
|
// Need this as I can't think of another way for an actor component to make sure it isn't on the server
|
||||||
inline bool IsLocallyControlled() const
|
inline bool IsLocallyControlled() const
|
||||||
{
|
{
|
||||||
#if ENGINE_MAJOR_VERSION > 4 || (ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 22)
|
//#if ENGINE_MAJOR_VERSION > 4 || (ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 22)
|
||||||
const AActor* MyOwner = GetOwner();
|
const AActor* MyOwner = GetOwner();
|
||||||
return MyOwner->HasLocalNetOwner();
|
return MyOwner->HasLocalNetOwner();
|
||||||
#else
|
//#else
|
||||||
// I like epics new authority check more than mine
|
// I like epics new authority check more than mine
|
||||||
const AActor* MyOwner = GetOwner();
|
/* const AActor* MyOwner = GetOwner();
|
||||||
const APawn* MyPawn = Cast<APawn>(MyOwner);
|
const APawn* MyPawn = Cast<APawn>(MyOwner);
|
||||||
|
|
||||||
return MyPawn ? MyPawn->IsLocallyControlled() : (MyOwner && MyOwner->GetLocalRole() == ENetRole::ROLE_Authority);
|
return MyPawn ? MyPawn->IsLocallyControlled() : (MyOwner && MyOwner->GetLocalRole() == ENetRole::ROLE_Authority);*/
|
||||||
#endif
|
//#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using tick and not timers because skeletal components tick anyway, kind of a waste to make another tick by adding a timer over that
|
// Using tick and not timers because skeletal components tick anyway, kind of a waste to make another tick by adding a timer over that
|
||||||
|
|
|
@ -7214,10 +7214,10 @@ void UGripMotionControllerComponent::ApplyTrackingParameters(FVector& OriginalPo
|
||||||
if (GEngine->XRSystem->GetCurrentPose(IXRTrackingSystem::HMDDeviceId, curRot, curLoc))
|
if (GEngine->XRSystem->GetCurrentPose(IXRTrackingSystem::HMDDeviceId, curRot, curLoc))
|
||||||
{
|
{
|
||||||
|
|
||||||
if (IsValid(AttachChar) && AttachChar->VRReplicatedCamera)
|
/*if (IsValid(AttachChar) && AttachChar->VRReplicatedCamera)
|
||||||
{
|
{
|
||||||
AttachChar->VRReplicatedCamera->ApplyTrackingParameters(curLoc, true);
|
AttachChar->VRReplicatedCamera->ApplyTrackingParameters(curLoc, true);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
//curLoc.Z = 0;
|
//curLoc.Z = 0;
|
||||||
LastLocationForLateUpdate = curLoc;
|
LastLocationForLateUpdate = curLoc;
|
||||||
|
@ -7234,7 +7234,7 @@ void UGripMotionControllerComponent::ApplyTrackingParameters(FVector& OriginalPo
|
||||||
if (IsValid(AttachChar) && AttachChar->VRReplicatedCamera)
|
if (IsValid(AttachChar) && AttachChar->VRReplicatedCamera)
|
||||||
{
|
{
|
||||||
// Sample camera location instead
|
// Sample camera location instead
|
||||||
LastLocationForLateUpdate = AttachChar->VRReplicatedCamera->GetRelativeLocation();
|
LastLocationForLateUpdate = AttachChar->VRReplicatedCamera->ReplicatedCameraTransform.Position; //GetRelativeLocation();
|
||||||
|
|
||||||
if (!AttachChar->bRetainRoomscale && IsLocallyControlled())
|
if (!AttachChar->bRetainRoomscale && IsLocallyControlled())
|
||||||
{
|
{
|
||||||
|
|
|
@ -54,7 +54,7 @@ AGrippableActor::AGrippableActor(const FObjectInitializer& ObjectInitializer)
|
||||||
|
|
||||||
// Setting a minimum of every 3rd frame (VR 90fps) for replication consideration
|
// Setting a minimum of every 3rd frame (VR 90fps) for replication consideration
|
||||||
// Otherwise we will get some massive slow downs if the replication is allowed to hit the 2 per second minimum default
|
// Otherwise we will get some massive slow downs if the replication is allowed to hit the 2 per second minimum default
|
||||||
MinNetUpdateFrequency = 30.0f;
|
SetMinNetUpdateFrequency(30.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AGrippableActor::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty > & OutLifetimeProps) const
|
void AGrippableActor::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty > & OutLifetimeProps) const
|
||||||
|
@ -152,15 +152,25 @@ void AGrippableActor::GatherCurrentMovement()
|
||||||
bool bFoundInCache = false;
|
bool bFoundInCache = false;
|
||||||
|
|
||||||
UWorld* World = GetWorld();
|
UWorld* World = GetWorld();
|
||||||
|
|
||||||
|
const bool bShouldUsePhysicsReplicationCache = GetPhysicsReplicationMode() != EPhysicsReplicationMode::Default;
|
||||||
int ServerFrame = 0;
|
int ServerFrame = 0;
|
||||||
|
|
||||||
|
if (bShouldUsePhysicsReplicationCache)
|
||||||
|
{
|
||||||
if (FPhysScene_Chaos* Scene = static_cast<FPhysScene_Chaos*>(World->GetPhysicsScene()))
|
if (FPhysScene_Chaos* Scene = static_cast<FPhysScene_Chaos*>(World->GetPhysicsScene()))
|
||||||
{
|
{
|
||||||
if (const FRigidBodyState* FoundState = Scene->GetStateFromReplicationCache(RootPrimComp, ServerFrame))
|
if (const FRigidBodyState* FoundState = Scene->GetStateFromReplicationCache(RootPrimComp, /*OUT*/ServerFrame))
|
||||||
{
|
{
|
||||||
RepMovement.FillFrom(*FoundState, this, Scene->ReplicationCache.ServerFrame);
|
if (RepMovement.ServerFrame != ServerFrame)
|
||||||
|
{
|
||||||
|
RepMovement.FillFrom(*FoundState, this, ServerFrame);
|
||||||
|
bWasRepMovementModified = true;
|
||||||
|
}
|
||||||
bFoundInCache = true;
|
bFoundInCache = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!bFoundInCache)
|
if (!bFoundInCache)
|
||||||
{
|
{
|
||||||
|
|
|
@ -52,9 +52,16 @@ namespace PhysicsReplicationCVars
|
||||||
|
|
||||||
int32 EnableDefaultReplication = 0;
|
int32 EnableDefaultReplication = 0;
|
||||||
|
|
||||||
|
namespace DefaultReplicationCVars
|
||||||
|
{
|
||||||
|
bool bHardsnapLegacyInPT = false;
|
||||||
|
bool bCorrectConnectedBodies = false;
|
||||||
|
bool bCorrectConnectedBodiesFriction = true;
|
||||||
|
}
|
||||||
|
|
||||||
namespace ResimulationCVars
|
namespace ResimulationCVars
|
||||||
{
|
{
|
||||||
bool bRuntimeCorrectionEnabled = true;
|
bool bRuntimeCorrectionEnabled = false;
|
||||||
bool bRuntimeVelocityCorrection = false;
|
bool bRuntimeVelocityCorrection = false;
|
||||||
bool bRuntimeCorrectConnectedBodies = true;
|
bool bRuntimeCorrectConnectedBodies = true;
|
||||||
float PosStabilityMultiplier = 0.5f;
|
float PosStabilityMultiplier = 0.5f;
|
||||||
|
@ -62,6 +69,18 @@ namespace PhysicsReplicationCVars
|
||||||
float VelStabilityMultiplier = 0.5f;
|
float VelStabilityMultiplier = 0.5f;
|
||||||
float AngVelStabilityMultiplier = 0.5f;
|
float AngVelStabilityMultiplier = 0.5f;
|
||||||
bool bDrawDebug = false;
|
bool bDrawDebug = false;
|
||||||
|
|
||||||
|
// Inside of NetworkPhysicsComponent - UPDATE AS CHANGE
|
||||||
|
int32 RedundantInputs = 2;
|
||||||
|
int32 RedundantStates = 0;
|
||||||
|
bool bAllowRewindToClosestState = true;
|
||||||
|
bool bCompareStateToTriggerRewind = false;
|
||||||
|
bool bCompareInputToTriggerRewind = false;
|
||||||
|
bool bEnableUnreliableFlow = true;
|
||||||
|
bool bEnableReliableFlow = false;
|
||||||
|
bool bApplyDataInsteadOfMergeData = false;
|
||||||
|
bool bAllowInputExtrapolation = true;
|
||||||
|
bool bValidateDataOnGameThread = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace PredictiveInterpolationCVars
|
namespace PredictiveInterpolationCVars
|
||||||
|
@ -92,15 +111,24 @@ namespace PhysicsReplicationCVars
|
||||||
bool bSkipVelocityRepOnPosEarlyOut = true;
|
bool bSkipVelocityRepOnPosEarlyOut = true;
|
||||||
bool bPostResimWaitForUpdate = false;
|
bool bPostResimWaitForUpdate = false;
|
||||||
bool bVelocityBased = true;
|
bool bVelocityBased = true;
|
||||||
bool bPosCorrectionAsVelocity = false;
|
|
||||||
|
// New or re-named 5.5
|
||||||
|
bool bCorrectionAsVelocity = false;
|
||||||
|
bool bCorrectConnectedBodies = false;
|
||||||
|
bool bCorrectConnectedBodiesFriction = true;
|
||||||
|
bool bSleepConnectedBodies = true;
|
||||||
|
bool bKinematicPrediction = true;
|
||||||
|
bool bKinematicHardSnap = false;
|
||||||
|
|
||||||
bool bDisableSoftSnap = false;
|
bool bDisableSoftSnap = false;
|
||||||
bool bAlwaysHardSnap = false;
|
bool bAlwaysHardSnap = false;
|
||||||
bool bSkipReplication = false;
|
bool bSkipReplication = false;
|
||||||
bool bDontClearTarget = false;
|
bool bDontClearTarget = false;
|
||||||
bool bDrawDebugTargets = false;
|
bool bDrawDebugTargets = false;
|
||||||
bool bDrawDebugVectors = false;
|
bool bDrawDebugVectors = false;
|
||||||
|
float DrawDebugZOffset = 50.0f;
|
||||||
float SleepSecondsClearTarget = 15.0f;
|
float SleepSecondsClearTarget = 15.0f;
|
||||||
int32 TargetTickAlignmentClampMultiplier = 1;
|
int32 TargetTickAlignmentClampMultiplier = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -482,7 +510,25 @@ bool FPhysicsReplicationVR::ApplyRigidBodyState(float DeltaSeconds, FBodyInstanc
|
||||||
const float AngularVelocityCoefficient = CVarAngLerp->GetFloat() >= 0.0f ? CVarAngLerp->GetFloat() : ErrorCorrection.AngularVelocityCoefficient;
|
const float AngularVelocityCoefficient = CVarAngLerp->GetFloat() >= 0.0f ? CVarAngLerp->GetFloat() : ErrorCorrection.AngularVelocityCoefficient;
|
||||||
|
|
||||||
static const auto CVarMaxLinearHardSnapDistance = IConsoleManager::Get().FindConsoleVariable(TEXT("p.MaxLinearHardSnapDistance"));
|
static const auto CVarMaxLinearHardSnapDistance = IConsoleManager::Get().FindConsoleVariable(TEXT("p.MaxLinearHardSnapDistance"));
|
||||||
const float MaxLinearHardSnapDistance = CVarMaxLinearHardSnapDistance->GetFloat() >= 0.f ? CVarMaxLinearHardSnapDistance->GetFloat() : ErrorCorrection.MaxLinearHardSnapDistance;
|
float MaxLinearHardSnapDistance = CVarMaxLinearHardSnapDistance->GetFloat() >= 0.f ? CVarMaxLinearHardSnapDistance->GetFloat() : ErrorCorrection.MaxLinearHardSnapDistance;
|
||||||
|
|
||||||
|
static const auto CVarHardsnapLegacyInPT = IConsoleManager::Get().FindConsoleVariable(TEXT("p.DefaultReplication.Legacy.HardsnapInPT"));
|
||||||
|
bool bHardsnapLegacyInPT = CVarHardsnapLegacyInPT->GetBool();
|
||||||
|
|
||||||
|
static const auto CVarCorrectConnectedBodies = IConsoleManager::Get().FindConsoleVariable(TEXT("p.DefaultReplication.CorrectConnectedBodies"));
|
||||||
|
bool bCorrectConnectedBodies = CVarCorrectConnectedBodies->GetBool();
|
||||||
|
|
||||||
|
static const auto CVarCorrectConnectedBodiesFriction = IConsoleManager::Get().FindConsoleVariable(TEXT("p.DefaultReplication.CorrectConnectedBodiesFriction"));
|
||||||
|
bool bCorrectConnectedBodiesFriction = CVarCorrectConnectedBodiesFriction->GetBool();
|
||||||
|
|
||||||
|
// Assign per-actor settings from NetworkPhysicSettingsComponent if this actor has one
|
||||||
|
if (SettingsCurrent.Get())
|
||||||
|
{
|
||||||
|
MaxLinearHardSnapDistance = SettingsCurrent.Get()->DefaultReplicationSettings.GetMaxLinearHardSnapDistance(MaxLinearHardSnapDistance);
|
||||||
|
bHardsnapLegacyInPT = SettingsCurrent.Get()->DefaultReplicationSettings.GetHardsnapDefaultLegacyInPT();
|
||||||
|
bCorrectConnectedBodies = SettingsCurrent.Get()->DefaultReplicationSettings.GetCorrectConnectedBodies();
|
||||||
|
bCorrectConnectedBodiesFriction = SettingsCurrent.Get()->DefaultReplicationSettings.GetCorrectConnectedBodiesFriction();
|
||||||
|
}
|
||||||
|
|
||||||
// Get Current state
|
// Get Current state
|
||||||
FRigidBodyState CurrentState;
|
FRigidBodyState CurrentState;
|
||||||
|
@ -606,12 +652,47 @@ bool FPhysicsReplicationVR::ApplyRigidBodyState(float DeltaSeconds, FBodyInstanc
|
||||||
// Too much error so just snap state here and be done with it
|
// Too much error so just snap state here and be done with it
|
||||||
PhysicsTarget.AccumulatedErrorSeconds = 0.0f;
|
PhysicsTarget.AccumulatedErrorSeconds = 0.0f;
|
||||||
bRestoredState = true;
|
bRestoredState = true;
|
||||||
|
// Hardsnap in physics thread
|
||||||
|
bool bPTHardSnapSuccess = false;
|
||||||
|
|
||||||
|
if (PhysicsReplicationAsyncVR != nullptr)
|
||||||
|
{
|
||||||
|
if (bHardsnapLegacyInPT)
|
||||||
|
{
|
||||||
|
if (Chaos::FSingleParticlePhysicsProxy* Proxy = static_cast<Chaos::FSingleParticlePhysicsProxy*>(BI->GetPhysicsActorHandle()))
|
||||||
|
{
|
||||||
|
if (Chaos::FPBDRigidsSolver* Solver = Proxy->GetSolver<Chaos::FPBDRigidsSolver>())
|
||||||
|
{
|
||||||
|
Solver->EnqueueCommandImmediate([Solver, Proxy, IdealWorldTM, NewState, bCorrectConnectedBodies, bCorrectConnectedBodiesFriction]()
|
||||||
|
{
|
||||||
|
Chaos::FRigidBodyHandle_Internal* Handle = Proxy->GetPhysicsThreadAPI();
|
||||||
|
|
||||||
|
// Set XRVW to hard snap dynamic object and force recalculation of friction
|
||||||
|
Solver->GetEvolution()->ApplyParticleTransformCorrection(Proxy->GetHandle_LowLevel(), IdealWorldTM.GetLocation(), IdealWorldTM.GetRotation(), bCorrectConnectedBodies, bCorrectConnectedBodiesFriction);
|
||||||
|
|
||||||
|
Handle->SetV(NewState.LinVel);
|
||||||
|
Handle->SetW(FMath::DegreesToRadians(NewState.AngVel));
|
||||||
|
});
|
||||||
|
|
||||||
|
bPTHardSnapSuccess = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bPTHardSnapSuccess)
|
||||||
|
{
|
||||||
BI->SetBodyTransform(IdealWorldTM, ETeleportType::ResetPhysics, bAutoWake);
|
BI->SetBodyTransform(IdealWorldTM, ETeleportType::ResetPhysics, bAutoWake);
|
||||||
|
|
||||||
// Set the new velocities
|
// Set the new velocities
|
||||||
BI->SetLinearVelocity(NewState.LinVel, false, bAutoWake);
|
BI->SetLinearVelocity(NewState.LinVel, false, bAutoWake);
|
||||||
BI->SetAngularVelocityInRadians(FMath::DegreesToRadians(NewState.AngVel), false, bAutoWake);
|
BI->SetAngularVelocityInRadians(FMath::DegreesToRadians(NewState.AngVel), false, bAutoWake);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the new velocities
|
||||||
|
BI->SetLinearVelocity(NewState.LinVel, false, bAutoWake);
|
||||||
|
BI->SetAngularVelocityInRadians(FMath::DegreesToRadians(NewState.AngVel), false, bAutoWake);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Small enough error to interpolate
|
// Small enough error to interpolate
|
||||||
|
@ -714,7 +795,8 @@ void FPhysicsReplicationVR::OnTick(float DeltaSeconds, TMap<TWeakObjectPtr<UPrim
|
||||||
|
|
||||||
|
|
||||||
int32 LocalFrameOffset = 0; // LocalFrame = ServerFrame + LocalFrameOffset;
|
int32 LocalFrameOffset = 0; // LocalFrame = ServerFrame + LocalFrameOffset;
|
||||||
if (FPhysicsSolverBase::IsNetworkPhysicsPredictionEnabled())
|
bool LocalFrameOffsetAssigned = false;
|
||||||
|
if (UPhysicsSettings::Get()->PhysicsPrediction.bEnablePhysicsPrediction)
|
||||||
{
|
{
|
||||||
if (UWorld* World = GetOwningWorld())
|
if (UWorld* World = GetOwningWorld())
|
||||||
{
|
{
|
||||||
|
@ -722,6 +804,7 @@ void FPhysicsReplicationVR::OnTick(float DeltaSeconds, TMap<TWeakObjectPtr<UPrim
|
||||||
{
|
{
|
||||||
if (APlayerController* PlayerController = World->GetFirstPlayerController())
|
if (APlayerController* PlayerController = World->GetFirstPlayerController())
|
||||||
{
|
{
|
||||||
|
LocalFrameOffsetAssigned = PlayerController->GetNetworkPhysicsTickOffsetAssigned();
|
||||||
LocalFrameOffset = PlayerController->GetNetworkPhysicsTickOffset();
|
LocalFrameOffset = PlayerController->GetNetworkPhysicsTickOffset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -753,6 +836,9 @@ void FPhysicsReplicationVR::OnTick(float DeltaSeconds, TMap<TWeakObjectPtr<UPrim
|
||||||
{
|
{
|
||||||
// Removed as this is server sided
|
// Removed as this is server sided
|
||||||
/*
|
/*
|
||||||
|
// Update actor replication settings overrides
|
||||||
|
SettingsCurrent = UNetworkPhysicsSettingsComponent::GetSettingsForActor(OwningActor);
|
||||||
|
|
||||||
const ENetRole OwnerRole = OwningActor->GetLocalRole();
|
const ENetRole OwnerRole = OwningActor->GetLocalRole();
|
||||||
const bool bIsSimulated = OwnerRole == ROLE_SimulatedProxy;
|
const bool bIsSimulated = OwnerRole == ROLE_SimulatedProxy;
|
||||||
const bool bIsReplicatedAutonomous = OwnerRole == ROLE_AutonomousProxy && PrimComp->bReplicatePhysicsToAutonomousProxy;
|
const bool bIsReplicatedAutonomous = OwnerRole == ROLE_AutonomousProxy && PrimComp->bReplicatePhysicsToAutonomousProxy;
|
||||||
|
@ -821,9 +907,14 @@ void FPhysicsReplicationVR::OnTick(float DeltaSeconds, TMap<TWeakObjectPtr<UPrim
|
||||||
|
|
||||||
AsyncInputData.RepMode = PhysicsTarget.ReplicationMode;
|
AsyncInputData.RepMode = PhysicsTarget.ReplicationMode;
|
||||||
AsyncInputData.ServerFrame = PhysicsTarget.ServerFrame;
|
AsyncInputData.ServerFrame = PhysicsTarget.ServerFrame;
|
||||||
AsyncInputData.FrameOffset = LocalFrameOffset;
|
|
||||||
AsyncInputData.LatencyOneWay = PingSecondsOneWay;
|
AsyncInputData.LatencyOneWay = PingSecondsOneWay;
|
||||||
|
|
||||||
|
if (LocalFrameOffsetAssigned)
|
||||||
|
{
|
||||||
|
AsyncInputData.FrameOffset = LocalFrameOffset;
|
||||||
|
}
|
||||||
|
|
||||||
AsyncInputVR->InputData.Add(AsyncInputData);
|
AsyncInputVR->InputData.Add(AsyncInputData);
|
||||||
}
|
}
|
||||||
ReplicatedTargetsQueueVR.Reset();
|
ReplicatedTargetsQueueVR.Reset();
|
||||||
|
@ -919,7 +1010,9 @@ bool FRepMovementVR::GatherActorsMovement(AActor* OwningActor)
|
||||||
|
|
||||||
void FPhysicsReplicationAsyncVR::OnPhysicsObjectUnregistered_Internal(Chaos::FConstPhysicsObjectHandle PhysicsObject)
|
void FPhysicsReplicationAsyncVR::OnPhysicsObjectUnregistered_Internal(Chaos::FConstPhysicsObjectHandle PhysicsObject)
|
||||||
{
|
{
|
||||||
ObjectToTarget.Remove(PhysicsObject);
|
RemoveObjectFromReplication(PhysicsObject);
|
||||||
|
|
||||||
|
// Only clear Settings when PhysicsObject unregister (not when it stops replicating, hence why it's not baked into RemoveObjectFromReplication())
|
||||||
ObjectToSettings.Remove(PhysicsObject);
|
ObjectToSettings.Remove(PhysicsObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -991,17 +1084,17 @@ void FPhysicsReplicationAsyncVR::OnPreSimulate_Internal()
|
||||||
if (Input.TargetState.Flags == ERigidBodyFlags::None)
|
if (Input.TargetState.Flags == ERigidBodyFlags::None)
|
||||||
{
|
{
|
||||||
// Remove replication target
|
// Remove replication target
|
||||||
ObjectToTarget.Remove(Input.PhysicsObject);
|
RemoveObjectFromReplication(Input.PhysicsObject);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bRewindDataExist && Input.RepMode == EPhysicsReplicationMode::Resimulation)
|
if (!bRewindDataExist && Input.RepMode == EPhysicsReplicationMode::Resimulation)
|
||||||
{
|
{
|
||||||
// We don't have rewind data but an actor is set to replicate using resimulation; we need to enable rewind capture.
|
// We don't have rewind data but an actor is set to replicate using resimulation; we need to enable rewind capture.
|
||||||
if (ensure(Chaos::FPBDRigidsSolver::IsNetworkPhysicsPredictionEnabled()))
|
if (ensure(Chaos::FPBDRigidsSolver::IsNetworkPhysicsPredictionEnabled() && RigidsSolver->IsUsingFixedDt()))
|
||||||
{
|
{
|
||||||
const int32 NumFrames = FMath::Max<int32>(1, Chaos::FPBDRigidsSolver::GetPhysicsHistoryCount());
|
|
||||||
RigidsSolver->EnableRewindCapture(NumFrames, true);
|
RigidsSolver->EnableRewindCapture();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1018,6 +1111,41 @@ void FPhysicsReplicationAsyncVR::OnPreSimulate_Internal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FReplicatedPhysicsTargetAsync* FPhysicsReplicationAsyncVR::AddObjectToReplication(Chaos::FConstPhysicsObjectHandle PhysicsObject)
|
||||||
|
{
|
||||||
|
if (ensure(PhysicsObject))
|
||||||
|
{
|
||||||
|
// Cache ParticleID in array of replicated objects
|
||||||
|
Chaos::FReadPhysicsObjectInterface_Internal Interface = Chaos::FPhysicsObjectInternalInterface::GetRead();
|
||||||
|
if (Chaos::FGeometryParticleHandle* Handle = Interface.GetParticle(PhysicsObject))
|
||||||
|
{
|
||||||
|
ReplicatedParticleIDs.Add(Handle->ParticleID());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to Object-Target map
|
||||||
|
return &ObjectToTarget.Add(PhysicsObject, FReplicatedPhysicsTargetAsync());
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FPhysicsReplicationAsyncVR::RemoveObjectFromReplication(Chaos::FConstPhysicsObjectHandle PhysicsObject)
|
||||||
|
{
|
||||||
|
if (PhysicsObject == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from Object-Target map
|
||||||
|
ObjectToTarget.Remove(PhysicsObject);
|
||||||
|
|
||||||
|
// Remove cached replicated ParticleID
|
||||||
|
Chaos::FReadPhysicsObjectInterface_Internal Interface = Chaos::FPhysicsObjectInternalInterface::GetRead();
|
||||||
|
if (Chaos::FGeometryParticleHandle* Handle = Interface.GetParticle(PhysicsObject))
|
||||||
|
{
|
||||||
|
ReplicatedParticleIDs.Remove(Handle->ParticleID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FPhysicsReplicationAsyncVR::UpdateRewindDataTarget(const FPhysicsRepAsyncInputData& Input)
|
void FPhysicsReplicationAsyncVR::UpdateRewindDataTarget(const FPhysicsRepAsyncInputData& Input)
|
||||||
{
|
{
|
||||||
if (Input.PhysicsObject == nullptr)
|
if (Input.PhysicsObject == nullptr)
|
||||||
|
@ -1025,6 +1153,12 @@ void FPhysicsReplicationAsyncVR::UpdateRewindDataTarget(const FPhysicsRepAsyncIn
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there is no FrameOffset set then we have not synced up physics ticks with the server yet so don't cache this data
|
||||||
|
if (Input.FrameOffset.IsSet() == false)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Chaos::FPBDRigidsSolver* RigidsSolver = static_cast<Chaos::FPBDRigidsSolver*>(GetSolver());
|
Chaos::FPBDRigidsSolver* RigidsSolver = static_cast<Chaos::FPBDRigidsSolver*>(GetSolver());
|
||||||
if (RigidsSolver == nullptr)
|
if (RigidsSolver == nullptr)
|
||||||
{
|
{
|
||||||
|
@ -1041,10 +1175,10 @@ void FPhysicsReplicationAsyncVR::UpdateRewindDataTarget(const FPhysicsRepAsyncIn
|
||||||
if (Chaos::FGeometryParticleHandle* Handle = Interface.GetParticle(Input.PhysicsObject))
|
if (Chaos::FGeometryParticleHandle* Handle = Interface.GetParticle(Input.PhysicsObject))
|
||||||
{
|
{
|
||||||
// Cache all target states inside RewindData
|
// Cache all target states inside RewindData
|
||||||
const int32 LocalFrame = Input.ServerFrame - Input.FrameOffset;
|
const int32 LocalFrame = Input.ServerFrame - *Input.FrameOffset;
|
||||||
RewindData->SetTargetStateAtFrame(*Handle, LocalFrame, Chaos::FFrameAndPhase::EParticleHistoryPhase::PostPushData,
|
RewindData->SetTargetStateAtFrame(*Handle, LocalFrame, Chaos::FFrameAndPhase::EParticleHistoryPhase::PostPushData,
|
||||||
Input.TargetState.Position, Input.TargetState.Quaternion,
|
Input.TargetState.Position, Input.TargetState.Quaternion,
|
||||||
Input.TargetState.LinVel, Input.TargetState.AngVel, (Input.TargetState.Flags & ERigidBodyFlags::Sleeping));
|
Input.TargetState.LinVel, FMath::DegreesToRadians(Input.TargetState.AngVel), (Input.TargetState.Flags & ERigidBodyFlags::Sleeping));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1060,7 +1194,7 @@ void FPhysicsReplicationAsyncVR::UpdateAsyncTarget(const FPhysicsRepAsyncInputDa
|
||||||
if (bFirstTarget)
|
if (bFirstTarget)
|
||||||
{
|
{
|
||||||
// First time we add a target, set previous state to current input
|
// First time we add a target, set previous state to current input
|
||||||
Target = &ObjectToTarget.Add(Input.PhysicsObject, FReplicatedPhysicsTargetAsync());
|
Target = AddObjectToReplication(Input.PhysicsObject);
|
||||||
Target->PrevPos = Input.TargetState.Position;
|
Target->PrevPos = Input.TargetState.Position;
|
||||||
Target->PrevPosTarget = Input.TargetState.Position;
|
Target->PrevPosTarget = Input.TargetState.Position;
|
||||||
Target->PrevRotTarget = Input.TargetState.Quaternion;
|
Target->PrevRotTarget = Input.TargetState.Quaternion;
|
||||||
|
@ -1107,6 +1241,9 @@ void FPhysicsReplicationAsyncVR::UpdateAsyncTarget(const FPhysicsRepAsyncInputDa
|
||||||
// Cache if this target was previously allowed to be altered, before this update
|
// Cache if this target was previously allowed to be altered, before this update
|
||||||
const bool bPrevAllowTargetAltering = Target->bAllowTargetAltering;
|
const bool bPrevAllowTargetAltering = Target->bAllowTargetAltering;
|
||||||
|
|
||||||
|
// Cache if the physics frame offset has changed since last target
|
||||||
|
const bool bFrameOffsetCorrected = Target->FrameOffset != Input.FrameOffset;
|
||||||
|
|
||||||
// Set if the target is allowed to be altered after this update
|
// Set if the target is allowed to be altered after this update
|
||||||
Target->bAllowTargetAltering = !(Target->TargetState.Flags & ERigidBodyFlags::Sleeping) && !(Input.TargetState.Flags & ERigidBodyFlags::Sleeping);
|
Target->bAllowTargetAltering = !(Target->TargetState.Flags & ERigidBodyFlags::Sleeping) && !(Input.TargetState.Flags & ERigidBodyFlags::Sleeping);
|
||||||
|
|
||||||
|
@ -1130,7 +1267,7 @@ void FPhysicsReplicationAsyncVR::UpdateAsyncTarget(const FPhysicsRepAsyncInputDa
|
||||||
Target->ReceiveFrame = CurrentFrame;
|
Target->ReceiveFrame = CurrentFrame;
|
||||||
Target->TargetState = Input.TargetState;
|
Target->TargetState = Input.TargetState;
|
||||||
Target->RepMode = Input.RepMode;
|
Target->RepMode = Input.RepMode;
|
||||||
Target->FrameOffset = Input.FrameOffset;
|
Target->FrameOffset = Input.FrameOffset.IsSet() ? *Input.FrameOffset : 0;
|
||||||
Target->TickCount = 0;
|
Target->TickCount = 0;
|
||||||
Target->AccumulatedSleepSeconds = 0.0f;
|
Target->AccumulatedSleepSeconds = 0.0f;
|
||||||
|
|
||||||
|
@ -1145,6 +1282,8 @@ void FPhysicsReplicationAsyncVR::UpdateAsyncTarget(const FPhysicsRepAsyncInputDa
|
||||||
if (CVarDrawDebugTargets->GetBool())
|
if (CVarDrawDebugTargets->GetBool())
|
||||||
{
|
{
|
||||||
const FVector Offset = FVector(0.0f, 0.0f, 50.0f);
|
const FVector Offset = FVector(0.0f, 0.0f, 50.0f);
|
||||||
|
// Port this?
|
||||||
|
//const FVector Offset = FVector(0.0f, 0.0f, PhysicsReplicationCVars::PredictiveInterpolationCVars::DrawDebugZOffset);
|
||||||
|
|
||||||
static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.NetCorrectionLifetime"));
|
static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.NetCorrectionLifetime"));
|
||||||
Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(Input.TargetState.Position + Offset, FVector(15.0f, 15.0f, 15.0f), Input.TargetState.Quaternion, FColor::MakeRandomSeededColor(Input.ServerFrame), false, CVarNetCorrectionLifetime->GetFloat(), 0, 1.0f);
|
Chaos::FDebugDrawQueue::GetInstance().DrawDebugBox(Input.TargetState.Position + Offset, FVector(15.0f, 15.0f, 15.0f), Input.TargetState.Quaternion, FColor::MakeRandomSeededColor(Input.ServerFrame), false, CVarNetCorrectionLifetime->GetFloat(), 0, 1.0f);
|
||||||
|
@ -1176,7 +1315,7 @@ void FPhysicsReplicationAsyncVR::UpdateAsyncTarget(const FPhysicsRepAsyncInputDa
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Run target alignment if we have been allowed to alter the target during the last two target updates
|
// Run target alignment if we have been allowed to alter the target during the last two target updates
|
||||||
if (!bFirstTarget && bPrevAllowTargetAltering && Target->bAllowTargetAltering)
|
if (!bFirstTarget && bPrevAllowTargetAltering && Target->bAllowTargetAltering && !bFrameOffsetCorrected)
|
||||||
{
|
{
|
||||||
static const auto CVarTargetTickAlignmentClampMultiplier = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.TargetTickAlignmentClampMultiplier"));
|
static const auto CVarTargetTickAlignmentClampMultiplier = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.TargetTickAlignmentClampMultiplier"));
|
||||||
const int32 AdjustedAverageReceiveInterval = FMath::CeilToInt(Target->AverageReceiveInterval) * CVarTargetTickAlignmentClampMultiplier->GetInt();
|
const int32 AdjustedAverageReceiveInterval = FMath::CeilToInt(Target->AverageReceiveInterval) * CVarTargetTickAlignmentClampMultiplier->GetInt();
|
||||||
|
@ -1257,6 +1396,7 @@ void FPhysicsReplicationAsyncVR::ApplyTargetStatesAsync(const float DeltaSeconds
|
||||||
for (auto Itr = ObjectToTarget.CreateIterator(); Itr; ++Itr)
|
for (auto Itr = ObjectToTarget.CreateIterator(); Itr; ++Itr)
|
||||||
{
|
{
|
||||||
bool bRemoveItr = true; // Remove current cached replication target unless replication logic tells us to store it for next tick
|
bool bRemoveItr = true; // Remove current cached replication target unless replication logic tells us to store it for next tick
|
||||||
|
FParticleID ParticleID;
|
||||||
|
|
||||||
Chaos::FConstPhysicsObjectHandle& POHandle = Itr.Key();
|
Chaos::FConstPhysicsObjectHandle& POHandle = Itr.Key();
|
||||||
if (FGeometryParticleHandle* Handle = Interface.GetParticle(POHandle))
|
if (FGeometryParticleHandle* Handle = Interface.GetParticle(POHandle))
|
||||||
|
@ -1266,6 +1406,8 @@ void FPhysicsReplicationAsyncVR::ApplyTargetStatesAsync(const float DeltaSeconds
|
||||||
|
|
||||||
if (FPBDRigidParticleHandle* RigidHandle = Handle->CastToRigidParticle())
|
if (FPBDRigidParticleHandle* RigidHandle = Handle->CastToRigidParticle())
|
||||||
{
|
{
|
||||||
|
ParticleID = RigidHandle->ParticleID();
|
||||||
|
|
||||||
// Cache custom settings for this object if there are any
|
// Cache custom settings for this object if there are any
|
||||||
FetchObjectSettings(POHandle);
|
FetchObjectSettings(POHandle);
|
||||||
|
|
||||||
|
@ -1290,6 +1432,7 @@ void FPhysicsReplicationAsyncVR::ApplyTargetStatesAsync(const float DeltaSeconds
|
||||||
|
|
||||||
if (bRemoveItr)
|
if (bRemoveItr)
|
||||||
{
|
{
|
||||||
|
ReplicatedParticleIDs.Remove(ParticleID);
|
||||||
Itr.RemoveCurrent();
|
Itr.RemoveCurrent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1463,7 +1606,8 @@ bool FPhysicsReplicationAsyncVR::DefaultReplication(Chaos::FPBDRigidParticleHand
|
||||||
const float AngularVelocityCoefficient = CVarAngLerp->GetFloat() >= 0.0f ? CVarAngLerp->GetFloat() : ErrorCorrectionDefault.AngularVelocityCoefficient;
|
const float AngularVelocityCoefficient = CVarAngLerp->GetFloat() >= 0.0f ? CVarAngLerp->GetFloat() : ErrorCorrectionDefault.AngularVelocityCoefficient;
|
||||||
|
|
||||||
static const auto CVarMaxLinearHardSnapDistance = IConsoleManager::Get().FindConsoleVariable(TEXT("p.MaxLinearHardSnapDistance"));
|
static const auto CVarMaxLinearHardSnapDistance = IConsoleManager::Get().FindConsoleVariable(TEXT("p.MaxLinearHardSnapDistance"));
|
||||||
const float MaxLinearHardSnapDistance = CVarMaxLinearHardSnapDistance->GetFloat() >= 0.f ? CVarMaxLinearHardSnapDistance->GetFloat() : ErrorCorrectionDefault.MaxLinearHardSnapDistance;
|
float MaxLinearHardSnapDistance = CVarMaxLinearHardSnapDistance->GetFloat() >= 0.f ? CVarMaxLinearHardSnapDistance->GetFloat() : ErrorCorrectionDefault.MaxLinearHardSnapDistance;
|
||||||
|
MaxLinearHardSnapDistance = SettingsCurrent.DefaultReplicationSettings.GetMaxLinearHardSnapDistance(MaxLinearHardSnapDistance);
|
||||||
|
|
||||||
// Get Current state
|
// Get Current state
|
||||||
FRigidBodyState CurrentState;
|
FRigidBodyState CurrentState;
|
||||||
|
@ -1582,8 +1726,11 @@ bool FPhysicsReplicationAsyncVR::DefaultReplication(Chaos::FPBDRigidParticleHand
|
||||||
// Too much error so just snap state here and be done with it
|
// Too much error so just snap state here and be done with it
|
||||||
Target.AccumulatedErrorSeconds = 0.0f;
|
Target.AccumulatedErrorSeconds = 0.0f;
|
||||||
bRestoredState = true;
|
bRestoredState = true;
|
||||||
Handle->SetX(TargetPos);
|
|
||||||
Handle->SetR(TargetQuat);
|
// Set XRVW to hard snap dynamic object and force recalculation of friction
|
||||||
|
const bool bCorrectConnectedBodies = SettingsCurrent.DefaultReplicationSettings.GetCorrectConnectedBodies();
|
||||||
|
const bool bCorrectConnectedBodiesFriction = SettingsCurrent.DefaultReplicationSettings.GetCorrectConnectedBodiesFriction();
|
||||||
|
RigidsSolver->GetEvolution()->ApplyParticleTransformCorrection(Handle, TargetPos, TargetQuat, bCorrectConnectedBodies, bCorrectConnectedBodiesFriction, ReplicatedParticleIDs);
|
||||||
Handle->SetV(NewState.LinVel);
|
Handle->SetV(NewState.LinVel);
|
||||||
Handle->SetW(FMath::DegreesToRadians(NewState.AngVel));
|
Handle->SetW(FMath::DegreesToRadians(NewState.AngVel));
|
||||||
}
|
}
|
||||||
|
@ -1651,6 +1798,8 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
||||||
static const auto CVarDrawDebugTargets = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.DrawDebugTargets"));
|
static const auto CVarDrawDebugTargets = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.DrawDebugTargets"));
|
||||||
if (CVarDrawDebugTargets->GetBool())
|
if (CVarDrawDebugTargets->GetBool())
|
||||||
{
|
{
|
||||||
|
// Needs updated post 5.5 for DrawDebugZ CVAR
|
||||||
|
|
||||||
const FVector Offset = FVector(0.0f, 0.0f, 50.0f);
|
const FVector Offset = FVector(0.0f, 0.0f, 50.0f);
|
||||||
const FVector StartPos = Target.TargetState.Position + Offset;
|
const FVector StartPos = Target.TargetState.Position + Offset;
|
||||||
const int32 SizeMultiplier = FMath::Clamp(Target.TickCount, -4, 30);
|
const int32 SizeMultiplier = FMath::Clamp(Target.TickCount, -4, 30);
|
||||||
|
@ -1675,15 +1824,21 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
||||||
if (bOkToClear && bShouldSleep && bCanSimulate)
|
if (bOkToClear && bShouldSleep && bCanSimulate)
|
||||||
{
|
{
|
||||||
RigidsSolver->GetEvolution()->SetParticleObjectState(Handle, Chaos::EObjectStateType::Sleeping);
|
RigidsSolver->GetEvolution()->SetParticleObjectState(Handle, Chaos::EObjectStateType::Sleeping);
|
||||||
|
|
||||||
|
static const auto CVarSleepConnectedBodies = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.SleepConnectedBodies"));
|
||||||
|
if (CVarSleepConnectedBodies->GetBool())
|
||||||
|
{
|
||||||
|
RigidsSolver->GetEvolution()->ApplySleepOnConnectedParticles(Handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const auto CVarSleepSecondsClearTarget = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.SleepSecondsClearTarget"));
|
static const auto CVarSleepSecondsClearTarget = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.SleepSecondsClearTarget"));
|
||||||
static const auto CVarDontClearTarget = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.DontClearTarget"));
|
static const auto CVarDontClearTarget = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.DontClearTarget"));
|
||||||
// --- Should replication stop? ---
|
// --- Should replication stop? ---
|
||||||
const bool bClearTarget =
|
const bool bClearTarget =
|
||||||
(!bCanSimulate
|
((bOkToClear && bShouldSleep && Target.AccumulatedSleepSeconds >= CVarSleepSecondsClearTarget->GetFloat()) // Allow clearing the target due to sleeping after the object has been sleeping for n seconds
|
||||||
|| (bOkToClear && bShouldSleep && Target.AccumulatedSleepSeconds >= CVarSleepSecondsClearTarget->GetFloat()) // Don't clear the target due to sleeping until the object both should sleep and is sleeping for n seconds
|
|| (bOkToClear && !bReplicatingPhysics) // If replication say it's okay to clear the target and the object shouldn't replicate physics anymore, clear the target
|
||||||
|| (bOkToClear && !bReplicatingPhysics))
|
|| (bOkToClear && !bCanSimulate)) // If replication say it's okay to clear the target and the object can't simulate, clear the target
|
||||||
&& !CVarDontClearTarget->GetBool();
|
&& !CVarDontClearTarget->GetBool();
|
||||||
|
|
||||||
// --- Target Prediction ---
|
// --- Target Prediction ---
|
||||||
|
@ -1694,10 +1849,16 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
||||||
const int32 ExtrapolationTickLimit = FMath::Max(
|
const int32 ExtrapolationTickLimit = FMath::Max(
|
||||||
FMath::CeilToInt(Target.AverageReceiveInterval * CVarExtrapolationTimeMultiplier->GetFloat()), // Extrapolate time based on receive interval * multiplier
|
FMath::CeilToInt(Target.AverageReceiveInterval * CVarExtrapolationTimeMultiplier->GetFloat()), // Extrapolate time based on receive interval * multiplier
|
||||||
FMath::CeilToInt(CVarExtrapolationMinTime->GetFloat() / DeltaSeconds)); // At least extrapolate for N seconds
|
FMath::CeilToInt(CVarExtrapolationMinTime->GetFloat() / DeltaSeconds)); // At least extrapolate for N seconds
|
||||||
|
|
||||||
if (Target.TickCount <= ExtrapolationTickLimit)
|
if (Target.TickCount <= ExtrapolationTickLimit)
|
||||||
{
|
{
|
||||||
FPhysicsReplicationAsyncVR::ExtrapolateTarget(Target, 1, DeltaSeconds);
|
FPhysicsReplicationAsyncVR::ExtrapolateTarget(Target, 1, DeltaSeconds);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If we reach the extrapolation limit, disable target from being altered
|
||||||
|
Target.bAllowTargetAltering = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bClearTarget;
|
return bClearTarget;
|
||||||
|
@ -1716,26 +1877,21 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
||||||
// Get the rotational offset between the blended rotation target and the current rotation
|
// Get the rotational offset between the blended rotation target and the current rotation
|
||||||
const FQuat TargetRotDelta = Target.TargetState.Quaternion * Handle->GetR().Inverse();
|
const FQuat TargetRotDelta = Target.TargetState.Quaternion * Handle->GetR().Inverse();
|
||||||
|
|
||||||
// Convert to angle axis
|
// Convert to angle and axis
|
||||||
float Angle;
|
float Angle;
|
||||||
FVector Axis;
|
FVector Axis;
|
||||||
TargetRotDelta.ToAxisAndAngle(Axis, Angle);
|
TargetRotDelta.ToAxisAndAngle(Axis, Angle);
|
||||||
Angle = FMath::Abs(FMath::UnwindRadians(Angle));
|
Angle = FMath::RadiansToDegrees(FMath::UnwindRadians(Angle));
|
||||||
|
Angle = FMath::Abs(Angle);
|
||||||
|
|
||||||
static const auto CVarEarlyOutAngle = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.EarlyOutAngle"));
|
static const auto CVarEarlyOutAngle = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.EarlyOutAngle"));
|
||||||
if (Angle < FMath::DegreesToRadians(CVarEarlyOutAngle->GetFloat()))
|
if (Angle < CVarEarlyOutAngle->GetFloat())
|
||||||
{
|
{
|
||||||
// Early Out
|
// Early Out
|
||||||
return EndReplicationHelper(Target, true);
|
return EndReplicationHelper(Target, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wake up if sleeping
|
|
||||||
if (bIsSleeping)
|
|
||||||
{
|
|
||||||
RigidsSolver->GetEvolution()->SetParticleObjectState(Handle, Chaos::EObjectStateType::Dynamic);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const auto CVarAverageReceiveIntervalSmoothing = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.AverageReceiveIntervalSmoothing"));
|
static const auto CVarAverageReceiveIntervalSmoothing = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.AverageReceiveIntervalSmoothing"));
|
||||||
// Update the AverageReceiveInterval if Target.ReceiveInterval has a valid value to update from
|
// Update the AverageReceiveInterval if Target.ReceiveInterval has a valid value to update from
|
||||||
Target.AverageReceiveInterval = Target.ReceiveInterval == 0 ? Target.AverageReceiveInterval : FMath::Lerp(Target.AverageReceiveInterval, Target.ReceiveInterval, FMath::Clamp((1.0f / (Target.ReceiveInterval * CVarAverageReceiveIntervalSmoothing->GetFloat())), 0.0f, 1.0f));
|
Target.AverageReceiveInterval = Target.ReceiveInterval == 0 ? Target.AverageReceiveInterval : FMath::Lerp(Target.AverageReceiveInterval, Target.ReceiveInterval, FMath::Clamp((1.0f / (Target.ReceiveInterval * CVarAverageReceiveIntervalSmoothing->GetFloat())), 0.0f, 1.0f));
|
||||||
|
@ -1745,13 +1901,13 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
||||||
CurrentState.Position = Handle->GetX();
|
CurrentState.Position = Handle->GetX();
|
||||||
CurrentState.Quaternion = Handle->GetR();
|
CurrentState.Quaternion = Handle->GetR();
|
||||||
CurrentState.LinVel = Handle->GetV();
|
CurrentState.LinVel = Handle->GetV();
|
||||||
CurrentState.AngVel = Handle->GetW(); // Note: Current angular velocity is in Radians
|
CurrentState.AngVel = Handle->GetW(); // Radians
|
||||||
|
|
||||||
// NewState
|
// NewState
|
||||||
const FVector TargetPos = FVector(Target.TargetState.Position);
|
const FVector TargetPos = FVector(Target.TargetState.Position);
|
||||||
const FQuat TargetRot = Target.TargetState.Quaternion;
|
const FQuat TargetRot = Target.TargetState.Quaternion;
|
||||||
const FVector TargetLinVel = FVector(Target.TargetState.LinVel);
|
const FVector TargetLinVel = FVector(Target.TargetState.LinVel);
|
||||||
const FVector TargetAngVel = FVector(Target.TargetState.AngVel); // Note: Target angular velocity is in Degrees
|
const FVector TargetAngVel = FVector(FMath::DegreesToRadians(Target.TargetState.AngVel)); // Radians
|
||||||
|
|
||||||
/** --- Reconciliation ---
|
/** --- Reconciliation ---
|
||||||
* If target velocities are low enough, check the traveled direction and distance from previous frame and compare with replicated linear velocity.
|
* If target velocities are low enough, check the traveled direction and distance from previous frame and compare with replicated linear velocity.
|
||||||
|
@ -1799,9 +1955,11 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
||||||
|
|
||||||
static const auto CVarErrorAccumulationSeconds = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.ErrorAccumulationSeconds"));
|
static const auto CVarErrorAccumulationSeconds = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.ErrorAccumulationSeconds"));
|
||||||
static const auto CVarAlwaysHardSnap = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.AlwaysHardSnap"));
|
static const auto CVarAlwaysHardSnap = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.AlwaysHardSnap"));
|
||||||
const bool bHardSnap = !bCanSimulate ||
|
static const auto CVarKinematicHardSnap = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.KinematicHardSnap"));
|
||||||
Target.AccumulatedErrorSeconds > CVarErrorAccumulationSeconds->GetFloat() ||
|
|
||||||
CVarAlwaysHardSnap->GetBool();
|
const bool bHardSnap = (!bCanSimulate && CVarKinematicHardSnap->GetBool())
|
||||||
|
|| Target.AccumulatedErrorSeconds > CVarErrorAccumulationSeconds->GetFloat()
|
||||||
|
|| CVarAlwaysHardSnap->GetBool();
|
||||||
|
|
||||||
if (bHardSnap)
|
if (bHardSnap)
|
||||||
{
|
{
|
||||||
|
@ -1815,13 +1973,13 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Set XPRQVW to hard snap dynamic object
|
// Set XRVW to hard snap dynamic object and force recalculation of friction
|
||||||
Handle->SetX(Target.PrevPosTarget);
|
const bool bCorrectConnectedBodies = SettingsCurrent.PredictiveInterpolationSettings.GetCorrectConnectedBodies();
|
||||||
Handle->SetP(Target.PrevPosTarget);
|
RigidsSolver->GetEvolution()->ApplyParticleTransformCorrection(Handle, Target.PrevPosTarget, Target.PrevRotTarget, bCorrectConnectedBodies, /*bInRecalculateFrictionOnConnectedBodies*/ true, ReplicatedParticleIDs);
|
||||||
Handle->SetR(Target.PrevRotTarget);
|
|
||||||
Handle->SetQ(Target.PrevRotTarget);
|
|
||||||
Handle->SetV(Target.TargetState.LinVel);
|
Handle->SetV(TargetLinVel);
|
||||||
Handle->SetW(FMath::DegreesToRadians(Target.TargetState.AngVel));
|
Handle->SetW(TargetAngVel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache data for next replication
|
// Cache data for next replication
|
||||||
|
@ -1830,8 +1988,72 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
||||||
// End replication and go to sleep if that's requested
|
// End replication and go to sleep if that's requested
|
||||||
return EndReplicationHelper(Target, true);
|
return EndReplicationHelper(Target, true);
|
||||||
}
|
}
|
||||||
|
else if (Handle->IsKinematic()) // Smooth Kinematic Replication
|
||||||
|
{
|
||||||
|
static const auto CVarKinematicPrediction = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.KinematicPrediction"));
|
||||||
|
const bool bKinematicPrediction = CVarKinematicPrediction->GetBool();
|
||||||
|
const float InterpolationTicks = FMath::CeilToInt(Target.AverageReceiveInterval) - (RigidsSolver->GetCurrentFrame() - Target.ReceiveFrame);
|
||||||
|
|
||||||
|
if ((bKinematicPrediction && Target.bAllowTargetAltering) || InterpolationTicks > 0)
|
||||||
|
{
|
||||||
|
/* Calculate the Lerp value for a smooth interpolation
|
||||||
|
* ------------------------------------------------------------------------------
|
||||||
|
* bKinematicPrediction is True :: Interpolate towards the target that gets forward predicted each tick
|
||||||
|
* 1 / 4 = 0.25 = 25% interpolation each time (if AverageReceiveInterval is 4)
|
||||||
|
* ------------------------------------------------------------------------------
|
||||||
|
* bKinematicPrediction is False :: Interpolate from current position to the static source for the current target, we need to cover the same amount of distance but from a decaying distance
|
||||||
|
* | ---> | ------------------ |
|
||||||
|
* 0% 25% 100% (1 / 4 = 0.25)
|
||||||
|
* | ---> | ----------- |
|
||||||
|
* 0% 33% 100% (1 / 3 = 0.33)
|
||||||
|
* | ---> | ---- |
|
||||||
|
* 0% 50% 100% (1 / 2 = 0.5)
|
||||||
|
* | ---> |
|
||||||
|
* 0% 100% (1 / 1 = 1.0)
|
||||||
|
* ------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
const float Lerp = 1.f / (bKinematicPrediction ? Target.AverageReceiveInterval : InterpolationTicks);
|
||||||
|
|
||||||
|
// Interpolate position and rotation from current position towards target position based on either predicted target or source target
|
||||||
|
const FVector KinTargetPos = FMath::Lerp(CurrentState.Position,
|
||||||
|
(bKinematicPrediction ? Target.TargetState.Position : Target.PrevPosTarget),
|
||||||
|
Lerp);
|
||||||
|
const FQuat KinTargetRot = FQuat::Slerp(CurrentState.Quaternion,
|
||||||
|
(bKinematicPrediction ? Target.TargetState.Quaternion : Target.PrevRotTarget),
|
||||||
|
Lerp);
|
||||||
|
|
||||||
|
// Apply kinematic target
|
||||||
|
const Chaos::FKinematicTarget KinTarget = Chaos::FKinematicTarget::MakePositionTarget(KinTargetPos, KinTargetRot); // Uses EKinematicTargetMode::Position
|
||||||
|
RigidsSolver->GetEvolution()->SetParticleKinematicTarget(Handle, KinTarget);
|
||||||
|
|
||||||
|
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
|
||||||
|
//static const auto CVarDrawDebugTargets = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.DrawDebugTargets"));
|
||||||
|
if (CVarDrawDebugTargets->GetBool())
|
||||||
|
{
|
||||||
|
|
||||||
|
static const auto CVarDrawDebugZOffset = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.DrawDebugZOffset"));
|
||||||
|
const FVector Offset = FVector(0.0f, 0.0f, CVarDrawDebugZOffset->GetFloat());
|
||||||
|
const FVector Pos = KinTargetPos + Offset;
|
||||||
|
const int32 SizeMultiplier = FMath::Clamp(Target.TickCount, -4, 30);
|
||||||
|
static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.NetCorrectionLifetime"));
|
||||||
|
Chaos::FDebugDrawQueue::GetInstance().DrawDebugSphere(Pos, 3.0f + SizeMultiplier * 0.75f, 8, FColor::MakeRandomSeededColor(Target.ServerFrame), false, CVarNetCorrectionLifetime->GetFloat(), 0, 1.0f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// End replication and allow to clear target
|
||||||
|
return EndReplicationHelper(Target, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
else // Velocity-based Replication
|
else // Velocity-based Replication
|
||||||
{
|
{
|
||||||
|
// Wake up if sleeping
|
||||||
|
if (bIsSleeping)
|
||||||
|
{
|
||||||
|
RigidsSolver->GetEvolution()->SetParticleObjectState(Handle, Chaos::EObjectStateType::Dynamic);
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate interpolation time based on current average receive rate
|
// Calculate interpolation time based on current average receive rate
|
||||||
const float AverageReceiveIntervalSeconds = Target.AverageReceiveInterval * DeltaSeconds;
|
const float AverageReceiveIntervalSeconds = Target.AverageReceiveInterval * DeltaSeconds;
|
||||||
const float InterpolationTime = AverageReceiveIntervalSeconds * SettingsCurrent.PredictiveInterpolationSettings.GetPosInterpolationTimeMultiplier();
|
const float InterpolationTime = AverageReceiveIntervalSeconds * SettingsCurrent.PredictiveInterpolationSettings.GetPosInterpolationTimeMultiplier();
|
||||||
|
@ -1843,6 +2065,7 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
||||||
const float RotCorrectionTime = FMath::Max(SettingsCurrent.PredictiveInterpolationSettings.GetRotCorrectionTimeBase() + AverageReceiveIntervalSeconds + RTT * SettingsCurrent.PredictiveInterpolationSettings.GetRotCorrectionTimeMultiplier(),
|
const float RotCorrectionTime = FMath::Max(SettingsCurrent.PredictiveInterpolationSettings.GetRotCorrectionTimeBase() + AverageReceiveIntervalSeconds + RTT * SettingsCurrent.PredictiveInterpolationSettings.GetRotCorrectionTimeMultiplier(),
|
||||||
DeltaSeconds + SettingsCurrent.PredictiveInterpolationSettings.GetRotCorrectionTimeMin());
|
DeltaSeconds + SettingsCurrent.PredictiveInterpolationSettings.GetRotCorrectionTimeMin());
|
||||||
|
|
||||||
|
FVector CorrectionX = CurrentState.Position;
|
||||||
if ((bXCanEarlyOut && SettingsCurrent.PredictiveInterpolationSettings.GetSkipVelocityRepOnPosEarlyOut()) == false)
|
if ((bXCanEarlyOut && SettingsCurrent.PredictiveInterpolationSettings.GetSkipVelocityRepOnPosEarlyOut()) == false)
|
||||||
{ // --- Velocity Replication ---
|
{ // --- Velocity Replication ---
|
||||||
|
|
||||||
|
@ -1853,10 +2076,10 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
||||||
const FVector LinVelDiff = -CurrentState.LinVel + TargetLinVel;
|
const FVector LinVelDiff = -CurrentState.LinVel + TargetLinVel;
|
||||||
|
|
||||||
// Calculate velocity blend amount for this tick as an alpha value
|
// Calculate velocity blend amount for this tick as an alpha value
|
||||||
const float Alpha = FMath::Clamp(DeltaSeconds / InterpolationTime, 0.0f, 1.0f);
|
const float VelocityAlpha = FMath::Clamp(DeltaSeconds / InterpolationTime, 0.0f, 1.0f);
|
||||||
|
|
||||||
FVector RepLinVel;
|
FVector RepLinVel;
|
||||||
static const auto CVarPosCorrectionAsVelocity = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.PosCorrectionAsVelocity"));
|
static const auto CVarPosCorrectionAsVelocity = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.CorrectionAsVelocity"));
|
||||||
if (CVarPosCorrectionAsVelocity->GetBool())
|
if (CVarPosCorrectionAsVelocity->GetBool())
|
||||||
{
|
{
|
||||||
// Convert PosDiff to a velocity
|
// Convert PosDiff to a velocity
|
||||||
|
@ -1866,20 +2089,21 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
||||||
const FVector BlendedTargetVelocity = LinVelDiff + PosDiffVelocity;
|
const FVector BlendedTargetVelocity = LinVelDiff + PosDiffVelocity;
|
||||||
|
|
||||||
// Add BlendedTargetVelocity onto current velocity
|
// Add BlendedTargetVelocity onto current velocity
|
||||||
|
RepLinVel = CurrentState.LinVel + (BlendedTargetVelocity * VelocityAlpha); // Same as (BlendedTargetVelocity / InterpolationTime) * DeltaSeconds
|
||||||
RepLinVel = CurrentState.LinVel + (BlendedTargetVelocity * Alpha);
|
|
||||||
}
|
}
|
||||||
else // Positional correction as position shift
|
else // Positional correction as transform shift
|
||||||
{
|
{
|
||||||
// Calculate the PosDiff amount to correct this tick
|
|
||||||
const FVector PosDiffVelocityDelta = PosDiff * (DeltaSeconds / PosCorrectionTime); // Same as (PosDiff / PosCorrectionTime) * DeltaSeconds
|
|
||||||
|
|
||||||
// Add velocity diff onto current velocity
|
// Add velocity diff onto current velocity
|
||||||
RepLinVel = CurrentState.LinVel + (LinVelDiff * Alpha);
|
RepLinVel = CurrentState.LinVel + (LinVelDiff * VelocityAlpha); // Same as (LinVelDiff / InterpolationTime) * DeltaSeconds
|
||||||
|
|
||||||
|
// Calculate correction blend amount for this tick as an alpha value
|
||||||
|
const float CorrectionAlpha = FMath::Clamp(DeltaSeconds / PosCorrectionTime, 0.0f, 1.0f);
|
||||||
|
|
||||||
// Apply positional correction
|
// Calculate the PosDiff amount to correct this tick
|
||||||
Handle->SetX(Handle->GetX() + PosDiffVelocityDelta);
|
const FVector PosDiffVelocityDelta = PosDiff * CorrectionAlpha; // Same as (PosDiff / PosCorrectionTime) * DeltaSeconds
|
||||||
|
|
||||||
|
// The new position after correction
|
||||||
|
CorrectionX = Handle->GetX() + PosDiffVelocityDelta;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply velocity replication
|
// Apply velocity replication
|
||||||
|
@ -1890,7 +2114,8 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
||||||
static const auto CVarDrawDebugVectors = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.DrawDebugVectors"));
|
static const auto CVarDrawDebugVectors = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.DrawDebugVectors"));
|
||||||
if (CVarDrawDebugVectors->GetBool())
|
if (CVarDrawDebugVectors->GetBool())
|
||||||
{
|
{
|
||||||
const FVector Offset = FVector(0.0f, 0.0f, 50.0f);
|
static const auto CVarDrawDebugZOffset = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.DrawDebugZOffset"));
|
||||||
|
const FVector Offset = FVector(0.0f, 0.0f, CVarDrawDebugZOffset->GetFloat());
|
||||||
const FVector OffsetAdd = FVector(0.0f, 0.0f, 10.0f);
|
const FVector OffsetAdd = FVector(0.0f, 0.0f, 10.0f);
|
||||||
const FVector StartPos = TargetPos + Offset;
|
const FVector StartPos = TargetPos + Offset;
|
||||||
FVector Direction = TargetLinVel;
|
FVector Direction = TargetLinVel;
|
||||||
|
@ -1908,37 +2133,63 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
||||||
Target.PrevLinVel = FVector(RepLinVel);
|
Target.PrevLinVel = FVector(RepLinVel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FQuat CorrectionR = CurrentState.Quaternion;
|
||||||
{ // --- Angular Velocity Replication ---
|
{ // --- Angular Velocity Replication ---
|
||||||
/* Todo, Implement InterpolationTime */
|
|
||||||
|
|
||||||
// Extrapolate current rotation along current angular velocity to see where we would end up
|
// Get AngVelDiff by adding inverted CurrentState.AngVel to TargetAngVel
|
||||||
float CurAngVelSize;
|
const FVector AngVelDiff = -CurrentState.AngVel + TargetAngVel;
|
||||||
FVector CurAngVelAxis;
|
|
||||||
CurrentState.AngVel.FVector::ToDirectionAndLength(CurAngVelAxis, CurAngVelSize);
|
|
||||||
const FQuat CurRotExtrapDelta = FQuat(CurAngVelAxis, CurAngVelSize * DeltaSeconds);
|
|
||||||
const FQuat CurRotExtrap = CurRotExtrapDelta * CurrentState.Quaternion;
|
|
||||||
|
|
||||||
// Slerp from the extrapolated current rotation towards the target rotation
|
// Calculate velocity blend amount for this tick as an alpha value
|
||||||
// This takes current angular velocity into account
|
const float VelocityAlpha = FMath::Clamp(DeltaSeconds / InterpolationTime, 0.0f, 1.0f);
|
||||||
const float RotCorrectionAmount = FMath::Clamp(DeltaSeconds / RotCorrectionTime, 0.0f, 1.0f);
|
|
||||||
const FQuat TargetRotBlended = FQuat::Slerp(CurRotExtrap, TargetRot, RotCorrectionAmount);
|
|
||||||
|
|
||||||
// Get the rotational offset between the blended rotation target and the current rotation
|
FVector RepAngVel;
|
||||||
const FQuat TargetRotDelta = TargetRotBlended * CurrentState.Quaternion.Inverse();
|
static const auto CVarCorrectionAsVelocity = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.CorrectionAsVelocity"));
|
||||||
|
if (CVarCorrectionAsVelocity->GetBool())
|
||||||
|
{
|
||||||
|
// Get RotDiff
|
||||||
|
const FQuat RotDiff = TargetRot * CurrentState.Quaternion.Inverse();
|
||||||
|
|
||||||
// Convert the rotational delta to angular velocity
|
// Convert RotDiff to a velocity
|
||||||
float WAngle;
|
float WAngle;
|
||||||
FVector WAxis;
|
FVector WAxis;
|
||||||
TargetRotDelta.ToAxisAndAngle(WAxis, WAngle);
|
RotDiff.ToAxisAndAngle(WAxis, WAngle);
|
||||||
const FVector TargetRotDeltaBlend = FVector(WAxis * (WAngle / (DeltaSeconds * SettingsCurrent.PredictiveInterpolationSettings.GetRotInterpolationTimeMultiplier())));
|
WAngle = FMath::UnwindRadians(WAngle);
|
||||||
const FVector RepAngVel = FMath::DegreesToRadians(TargetAngVel) + TargetRotDeltaBlend;
|
const FVector RotDiffVelocity = FVector(WAxis * (WAngle / RotCorrectionTime));
|
||||||
|
|
||||||
|
// Add RotDiffVelocity to AngVelDiff to get BlendedTargetVelocity
|
||||||
|
const FVector BlendedTargetVelocity = AngVelDiff + RotDiffVelocity;
|
||||||
|
|
||||||
|
// Add BlendedTargetVelocity to CurrentState.AngVel
|
||||||
|
RepAngVel = CurrentState.AngVel + (BlendedTargetVelocity * VelocityAlpha); // Same as (BlendedTargetVelocity / InterpolationTime) * DeltaSeconds
|
||||||
|
}
|
||||||
|
else // Positional correction as transform shift
|
||||||
|
{
|
||||||
|
// Add velocity diff onto current velocity
|
||||||
|
RepAngVel = CurrentState.AngVel + (AngVelDiff * VelocityAlpha); // Same as (AngVelDiff / InterpolationTime) * DeltaSeconds
|
||||||
|
|
||||||
|
// Calculate correction blend amount for this tick as an alpha value
|
||||||
|
const float CorrectionAlpha = FMath::Clamp(DeltaSeconds / RotCorrectionTime, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
// The new position after correction
|
||||||
|
CorrectionR = FQuat::Slerp(Handle->GetR(), TargetRot, CorrectionAlpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply velocity replication
|
||||||
Handle->SetW(RepAngVel);
|
Handle->SetW(RepAngVel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache data for next replication
|
// Cache data for next replication
|
||||||
Target.PrevPos = FVector(CurrentState.Position);
|
Target.PrevPos = FVector(CurrentState.Position);
|
||||||
|
|
||||||
|
// Apply correction as a transform shift
|
||||||
|
static const auto CVarCorrectionAsVelocity = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.CorrectionAsVelocity"));
|
||||||
|
if (!CVarCorrectionAsVelocity->GetBool())
|
||||||
|
{
|
||||||
|
const bool bCorrectConnectedBodies = SettingsCurrent.PredictiveInterpolationSettings.GetCorrectConnectedBodies();
|
||||||
|
const bool bCorrectConnectedBodiesFriction = SettingsCurrent.PredictiveInterpolationSettings.GetCorrectConnectedBodiesFriction();
|
||||||
|
RigidsSolver->GetEvolution()->ApplyParticleTransformCorrection(Handle, CorrectionX, CorrectionR, bCorrectConnectedBodies, bCorrectConnectedBodiesFriction, ReplicatedParticleIDs);
|
||||||
|
}
|
||||||
|
|
||||||
if (bSoftSnap)
|
if (bSoftSnap)
|
||||||
{
|
{
|
||||||
const FVector SoftSnapPos = FMath::Lerp(FVector(CurrentState.Position),
|
const FVector SoftSnapPos = FMath::Lerp(FVector(CurrentState.Position),
|
||||||
|
@ -1949,10 +2200,10 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
||||||
SettingsCurrent.PredictiveInterpolationSettings.GetSoftSnapToSource() ? Target.PrevRotTarget : Target.TargetState.Quaternion,
|
SettingsCurrent.PredictiveInterpolationSettings.GetSoftSnapToSource() ? Target.PrevRotTarget : Target.TargetState.Quaternion,
|
||||||
FMath::Clamp(SettingsCurrent.PredictiveInterpolationSettings.GetSoftSnapRotStrength(), 0.0f, 1.0f));
|
FMath::Clamp(SettingsCurrent.PredictiveInterpolationSettings.GetSoftSnapRotStrength(), 0.0f, 1.0f));
|
||||||
|
|
||||||
Handle->SetX(SoftSnapPos);
|
// Apply correction as a transform shift
|
||||||
Handle->SetP(SoftSnapPos);
|
const bool bCorrectConnectedBodies = SettingsCurrent.PredictiveInterpolationSettings.GetCorrectConnectedBodies();
|
||||||
Handle->SetR(SoftSnapRot);
|
const bool bCorrectConnectedBodiesFriction = SettingsCurrent.PredictiveInterpolationSettings.GetCorrectConnectedBodiesFriction();
|
||||||
Handle->SetQ(SoftSnapRot);
|
RigidsSolver->GetEvolution()->ApplyParticleTransformCorrection(Handle, SoftSnapPos, SoftSnapRot, bCorrectConnectedBodies, bCorrectConnectedBodiesFriction, ReplicatedParticleIDs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2003,17 +2254,48 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool bShouldSleep = (Target.TargetState.Flags & ERigidBodyFlags::Sleeping) != 0;
|
||||||
bool bClearTarget = true;
|
bool bClearTarget = true;
|
||||||
|
|
||||||
|
|
||||||
static constexpr Chaos::FFrameAndPhase::EParticleHistoryPhase RewindPhase = Chaos::FFrameAndPhase::EParticleHistoryPhase::PostPushData;
|
static constexpr Chaos::FFrameAndPhase::EParticleHistoryPhase RewindPhase = Chaos::FFrameAndPhase::EParticleHistoryPhase::PostPushData;
|
||||||
|
|
||||||
const float ResimErrorThreshold = SettingsCurrent.ResimulationSettings.GetResimulationErrorThreshold(Chaos::FPhysicsSolverBase::ResimulationErrorThreshold());
|
// Get state from locally cached history for frame corresponding to received data
|
||||||
const Chaos::FGeometryParticleState PastState = RewindData->GetPastStateAtFrame(*Handle, LocalFrame, RewindPhase);
|
const Chaos::FGeometryParticleState PastState = RewindData->GetPastStateAtFrame(*Handle, LocalFrame, RewindPhase);
|
||||||
|
|
||||||
const FVector ErrorOffset = (Target.TargetState.Position - PastState.GetX());
|
// Check which comparisons to perform to trigger resimulation from
|
||||||
const float ErrorDistance = ErrorOffset.Size();
|
const bool bCompareX = Chaos::FPhysicsSolverBase::GetResimulationErrorPositionThresholdEnabled() || SettingsCurrent.ResimulationSettings.bOverrideResimulationErrorPositionThreshold;
|
||||||
const bool ShouldTriggerResim = ErrorDistance >= ResimErrorThreshold;
|
const bool bCompareR = Chaos::FPhysicsSolverBase::GetResimulationErrorRotationThresholdEnabled() || SettingsCurrent.ResimulationSettings.bOverrideResimulationErrorRotationThreshold;
|
||||||
|
const bool bCompareV = Chaos::FPhysicsSolverBase::GetResimulationErrorLinearVelocityThresholdEnabled() || SettingsCurrent.ResimulationSettings.bOverrideResimulationErrorLinearVelocityThreshold;
|
||||||
|
const bool bCompareW = Chaos::FPhysicsSolverBase::GetResimulationErrorAngularVelocityThresholdEnabled() || SettingsCurrent.ResimulationSettings.bOverrideResimulationErrorAngularVelocityThreshold;
|
||||||
|
bool bShouldTriggerResim = false;
|
||||||
|
|
||||||
|
// Check for positional discrepancy in Distance between client and server
|
||||||
|
if (bCompareX)
|
||||||
|
{
|
||||||
|
const float ResimPositionErrorThreshold = SettingsCurrent.ResimulationSettings.GetResimulationErrorPositionThreshold(Chaos::FPhysicsSolverBase::GetResimulationErrorPositionThreshold());
|
||||||
|
bShouldTriggerResim = Chaos::FRewindData::CheckVectorThreshold(Target.TargetState.Position, PastState.GetX(), ResimPositionErrorThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for linear velocity discrepancy in Distance / s between client and server
|
||||||
|
if (!bShouldTriggerResim && bCompareV)
|
||||||
|
{
|
||||||
|
const float ResimLinVelocityErrorThreshold = SettingsCurrent.ResimulationSettings.GetResimulationErrorLinearVelocityThreshold(Chaos::FPhysicsSolverBase::GetResimulationErrorLinearVelocityThreshold());
|
||||||
|
bShouldTriggerResim = Chaos::FRewindData::CheckVectorThreshold(Target.TargetState.LinVel, PastState.GetV(), ResimLinVelocityErrorThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for angular velocity discrepancy in Degrees / s between client and server
|
||||||
|
if (!bShouldTriggerResim && bCompareW)
|
||||||
|
{
|
||||||
|
const float ResimAngVelocityErrorThreshold = SettingsCurrent.ResimulationSettings.GetResimulationErrorAngularVelocityThreshold(Chaos::FPhysicsSolverBase::GetResimulationErrorAngularVelocityThreshold());
|
||||||
|
bShouldTriggerResim = Chaos::FRewindData::CheckVectorThreshold(FMath::DegreesToRadians(Target.TargetState.AngVel), PastState.GetW(), ResimAngVelocityErrorThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for rotational discrepancy in Degrees between client and server
|
||||||
|
if (!bShouldTriggerResim && bCompareR)
|
||||||
|
{
|
||||||
|
const float ResimRotationErrorThreshold = SettingsCurrent.ResimulationSettings.GetResimulationErrorRotationThreshold(Chaos::FPhysicsSolverBase::GetResimulationErrorRotationThreshold());
|
||||||
|
bShouldTriggerResim = Chaos::FRewindData::CheckQuaternionThreshold(Target.TargetState.Quaternion, PastState.GetR(), ResimRotationErrorThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
|
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
|
||||||
|
@ -2021,7 +2303,7 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
|
||||||
if (Chaos::FPhysicsSolverBase::CanDebugNetworkPhysicsPrediction())
|
if (Chaos::FPhysicsSolverBase::CanDebugNetworkPhysicsPrediction())
|
||||||
{
|
{
|
||||||
UE_LOG(LogTemp, Log, TEXT("Apply Rigid body state at local frame %d with offset = %d"), LocalFrame, Target.FrameOffset);
|
UE_LOG(LogTemp, Log, TEXT("Apply Rigid body state at local frame %d with offset = %d"), LocalFrame, Target.FrameOffset);
|
||||||
UE_LOG(LogTemp, Log, TEXT("Particle Position Error = %f | Should Trigger Resim = %s | Server Frame = %d | Client Frame = %d"), ErrorDistance, (ShouldTriggerResim ? TEXT("True") : TEXT("False")), Target.ServerFrame, LocalFrame);
|
UE_LOG(LogTemp, Log, TEXT("Should Trigger Resim = %s | Server Frame = %d | Client Frame = %d"), (bShouldTriggerResim ? TEXT("True") : TEXT("False")), Target.ServerFrame, LocalFrame);
|
||||||
UE_LOG(LogTemp, Log, TEXT("Particle Target Position = %s | Current Position = %s"), *Target.TargetState.Position.ToString(), *PastState.GetX().ToString());
|
UE_LOG(LogTemp, Log, TEXT("Particle Target Position = %s | Current Position = %s"), *Target.TargetState.Position.ToString(), *PastState.GetX().ToString());
|
||||||
UE_LOG(LogTemp, Log, TEXT("Particle Target Velocity = %s | Current Velocity = %s"), *Target.TargetState.LinVel.ToString(), *PastState.GetV().ToString());
|
UE_LOG(LogTemp, Log, TEXT("Particle Target Velocity = %s | Current Velocity = %s"), *Target.TargetState.LinVel.ToString(), *PastState.GetV().ToString());
|
||||||
UE_LOG(LogTemp, Log, TEXT("Particle Target Quaternion = %s | Current Quaternion = %s"), *Target.TargetState.Quaternion.ToString(), *PastState.GetR().ToString());
|
UE_LOG(LogTemp, Log, TEXT("Particle Target Quaternion = %s | Current Quaternion = %s"), *Target.TargetState.Quaternion.ToString(), *PastState.GetR().ToString());
|
||||||
|
@ -2032,7 +2314,7 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
|
||||||
if (CVarResimDrawDebug->GetBool())
|
if (CVarResimDrawDebug->GetBool())
|
||||||
{
|
{
|
||||||
static constexpr float BoxSize = 5.0f;
|
static constexpr float BoxSize = 5.0f;
|
||||||
const float ColorLerp = ShouldTriggerResim ? 1.0f : 0.0f;
|
const float ColorLerp = bShouldTriggerResim ? 1.0f : 0.0f;
|
||||||
const FColor DebugColor = FLinearColor::LerpUsingHSV(FLinearColor::Green, FLinearColor::Red, ColorLerp).ToFColor(false);
|
const FColor DebugColor = FLinearColor::LerpUsingHSV(FLinearColor::Green, FLinearColor::Red, ColorLerp).ToFColor(false);
|
||||||
|
|
||||||
static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.NetCorrectionLifetime"));
|
static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.NetCorrectionLifetime"));
|
||||||
|
@ -2042,9 +2324,13 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (LocalFrame > RewindData->GetBlockedResimFrame())
|
// Wake up if is sleeping and should not sleep
|
||||||
|
if (Handle->IsSleeping() && !bShouldSleep)
|
||||||
{
|
{
|
||||||
if (ShouldTriggerResim && Target.TickCount == 0)
|
RigidsSolver->GetEvolution()->SetParticleObjectState(Handle, Chaos::EObjectStateType::Dynamic);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bShouldTriggerResim && Target.TickCount == 0 && LocalFrame > RewindData->GetBlockedResimFrame())
|
||||||
{
|
{
|
||||||
// Trigger resimulation
|
// Trigger resimulation
|
||||||
RigidsSolver->GetEvolution()->GetIslandManager().SetParticleResimFrame(Handle, LocalFrame);
|
RigidsSolver->GetEvolution()->GetIslandManager().SetParticleResimFrame(Handle, LocalFrame);
|
||||||
|
@ -2054,23 +2340,20 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
|
||||||
RewindData->SetResimFrame(ResimFrame);
|
RewindData->SetResimFrame(ResimFrame);
|
||||||
}
|
}
|
||||||
else if (SettingsCurrent.ResimulationSettings.GetRuntimeCorrectionEnabled())
|
else if (SettingsCurrent.ResimulationSettings.GetRuntimeCorrectionEnabled())
|
||||||
|
|
||||||
{
|
{
|
||||||
const int32 NumPredictedFrames = RigidsSolver->GetCurrentFrame() - LocalFrame - Target.TickCount;
|
const int32 NumPredictedFrames = RigidsSolver->GetCurrentFrame() - LocalFrame - Target.TickCount;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (Target.TickCount <= NumPredictedFrames && NumPredictedFrames > 0)
|
if (Target.TickCount <= NumPredictedFrames && NumPredictedFrames > 0)
|
||||||
{
|
{
|
||||||
|
const FVector ErrorOffset = (Target.TargetState.Position - PastState.GetX());
|
||||||
|
|
||||||
// Positional Correction
|
// Positional Correction
|
||||||
const float CorrectionAmountX = SettingsCurrent.ResimulationSettings.GetPosStabilityMultiplier() / NumPredictedFrames;
|
const float CorrectionAmountX = SettingsCurrent.ResimulationSettings.GetPosStabilityMultiplier() / NumPredictedFrames;
|
||||||
const FVector PosDiffCorrection = ErrorOffset * CorrectionAmountX; // Same result as (ErrorOffset / NumPredictedFrames) * PosStabilityMultiplier
|
const FVector PosDiffCorrection = ErrorOffset * CorrectionAmountX; // Same result as (ErrorOffset / NumPredictedFrames) * PosStabilityMultiplier
|
||||||
const FVector CorrectedX = Handle->GetX() + PosDiffCorrection;
|
const FVector CorrectedX = Handle->GetX() + PosDiffCorrection;
|
||||||
|
|
||||||
|
|
||||||
// Rotational Correction
|
// Rotational Correction
|
||||||
const float CorrectionAmountR = SettingsCurrent.ResimulationSettings.GetRotStabilityMultiplier() / NumPredictedFrames;
|
const float CorrectionAmountR = SettingsCurrent.ResimulationSettings.GetRotStabilityMultiplier() / NumPredictedFrames;
|
||||||
|
|
||||||
const FQuat DeltaQuat = PastState.GetR().Inverse() * Target.TargetState.Quaternion;
|
const FQuat DeltaQuat = PastState.GetR().Inverse() * Target.TargetState.Quaternion;
|
||||||
const FQuat TargetCorrectionR = Handle->GetR() * DeltaQuat;
|
const FQuat TargetCorrectionR = Handle->GetR() * DeltaQuat;
|
||||||
const FQuat CorrectedR = FQuat::Slerp(Handle->GetR(), TargetCorrectionR, CorrectionAmountR);
|
const FQuat CorrectedR = FQuat::Slerp(Handle->GetR(), TargetCorrectionR, CorrectionAmountR);
|
||||||
|
@ -2084,7 +2367,7 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
|
||||||
const FVector CorrectedV = Handle->GetV() + VelCorrection;
|
const FVector CorrectedV = Handle->GetV() + VelCorrection;
|
||||||
|
|
||||||
// Angular Velocity Correction
|
// Angular Velocity Correction
|
||||||
const FVector AngVelDiff = Target.TargetState.AngVel - PastState.GetW(); // Angular velocity vector that the server covers but the client doesn't
|
const FVector AngVelDiff = FMath::DegreesToRadians(Target.TargetState.AngVel) - PastState.GetW(); // Angular velocity vector that the server covers but the client doesn't
|
||||||
const float CorrectionAmountW = SettingsCurrent.ResimulationSettings.GetAngVelStabilityMultiplier() / NumPredictedFrames;
|
const float CorrectionAmountW = SettingsCurrent.ResimulationSettings.GetAngVelStabilityMultiplier() / NumPredictedFrames;
|
||||||
const FVector AngVelCorrection = AngVelDiff * CorrectionAmountW; // Same result as (AngVelDiff / NumPredictedFrames) * VelStabilityMultiplier
|
const FVector AngVelCorrection = AngVelDiff * CorrectionAmountW; // Same result as (AngVelDiff / NumPredictedFrames) * VelStabilityMultiplier
|
||||||
const FVector CorrectedW = Handle->GetW() + AngVelCorrection;
|
const FVector CorrectedW = Handle->GetW() + AngVelCorrection;
|
||||||
|
@ -2103,14 +2386,27 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// Apply correction to position and rotation
|
// Apply correction to position and rotation
|
||||||
static const auto CVarResimRuntimeCorrectConnectedBodies = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.Resim.RuntimeCorrectConnectedBodies"));
|
RigidsSolver->GetEvolution()->ApplyParticleTransformCorrection(Handle, CorrectedX, CorrectedR, SettingsCurrent.ResimulationSettings.GetRuntimeCorrectConnectedBodies(), /*bInRecalculateFrictionOnConnectedBodies*/true, ReplicatedParticleIDs);
|
||||||
RigidsSolver->GetEvolution()->ApplyParticleTransformCorrection(Handle, CorrectedX, CorrectedR, CVarResimRuntimeCorrectConnectedBodies->GetBool());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep target for NumPredictedFrames time to perform runtime corrections with until a new target is received
|
// Keep target for NumPredictedFrames time to perform runtime corrections with until a new target is received
|
||||||
bClearTarget = Target.TickCount >= NumPredictedFrames;
|
bClearTarget = Target.TickCount >= NumPredictedFrames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set sleep state if we are about to clear the target from memory and the target is set to sleep
|
||||||
|
if (bClearTarget && bShouldSleep)
|
||||||
|
{
|
||||||
|
// Snap object into correct state, it should already be at that state or very close to it
|
||||||
|
RigidsSolver->GetEvolution()->ApplyParticleTransformCorrection(Handle, Target.TargetState.Position, Target.TargetState.Quaternion, /*bApplyToConnectedBodies*/true, /*bInRecalculateFrictionOnConnectedBodies*/true, ReplicatedParticleIDs);
|
||||||
|
|
||||||
|
RigidsSolver->GetEvolution()->SetParticleObjectState(Handle, Chaos::EObjectStateType::Sleeping);
|
||||||
|
static const auto CVarSleepConnectedBodies = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.SleepConnectedBodies"));
|
||||||
|
if (CVarSleepConnectedBodies->GetBool())
|
||||||
|
{
|
||||||
|
RigidsSolver->GetEvolution()->ApplySleepOnConnectedParticles(Handle);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return bClearTarget;
|
return bClearTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#include "PhysicsReplication.h"
|
#include "PhysicsReplication.h"
|
||||||
#include "Physics/Experimental/PhysScene_Chaos.h"
|
#include "Physics/Experimental/PhysScene_Chaos.h"
|
||||||
#include "PhysicsEngine/PhysicsAsset.h" // Tmp until epic bug fixes skeletal welding
|
#include "PhysicsEngine/PhysicsAsset.h" // Tmp until epic bug fixes skeletal welding
|
||||||
|
#include "PhysicsEngine/BodySetup.h"
|
||||||
|
#include "PhysicsEngine/SkeletalBodySetup.h"
|
||||||
#if WITH_PUSH_MODEL
|
#if WITH_PUSH_MODEL
|
||||||
#include "Net/Core/PushModel/PushModel.h"
|
#include "Net/Core/PushModel/PushModel.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -63,7 +65,7 @@ void UOptionalRepSkeletalMeshComponent::GetWeldedBodies(TArray<FBodyInstance*>&
|
||||||
OutWeldedBodies.Add(BI);
|
OutWeldedBodies.Add(BI);
|
||||||
if (PhysicsAsset)
|
if (PhysicsAsset)
|
||||||
{
|
{
|
||||||
if (UBodySetup* PhysicsAssetBodySetup = PhysicsAsset->SkeletalBodySetups[BodyIdx])
|
if (UBodySetup* PhysicsAssetBodySetup = PhysicsAsset->SkeletalBodySetups[BodyIdx].Get())
|
||||||
{
|
{
|
||||||
OutLabels.Add(PhysicsAssetBodySetup->BoneName);
|
OutLabels.Add(PhysicsAssetBodySetup->BoneName);
|
||||||
}
|
}
|
||||||
|
@ -156,7 +158,7 @@ AGrippableSkeletalMeshActor::AGrippableSkeletalMeshActor(const FObjectInitialize
|
||||||
|
|
||||||
// Setting a minimum of every 3rd frame (VR 90fps) for replication consideration
|
// Setting a minimum of every 3rd frame (VR 90fps) for replication consideration
|
||||||
// Otherwise we will get some massive slow downs if the replication is allowed to hit the 2 per second minimum default
|
// Otherwise we will get some massive slow downs if the replication is allowed to hit the 2 per second minimum default
|
||||||
MinNetUpdateFrequency = 30.0f;
|
SetMinNetUpdateFrequency(30.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AGrippableSkeletalMeshActor::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty >& OutLifetimeProps) const
|
void AGrippableSkeletalMeshActor::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty >& OutLifetimeProps) const
|
||||||
|
@ -254,15 +256,25 @@ void AGrippableSkeletalMeshActor::GatherCurrentMovement()
|
||||||
bool bFoundInCache = false;
|
bool bFoundInCache = false;
|
||||||
|
|
||||||
UWorld* World = GetWorld();
|
UWorld* World = GetWorld();
|
||||||
|
|
||||||
|
const bool bShouldUsePhysicsReplicationCache = GetPhysicsReplicationMode() != EPhysicsReplicationMode::Default;
|
||||||
int ServerFrame = 0;
|
int ServerFrame = 0;
|
||||||
|
|
||||||
|
if (bShouldUsePhysicsReplicationCache)
|
||||||
|
{
|
||||||
if (FPhysScene_Chaos* Scene = static_cast<FPhysScene_Chaos*>(World->GetPhysicsScene()))
|
if (FPhysScene_Chaos* Scene = static_cast<FPhysScene_Chaos*>(World->GetPhysicsScene()))
|
||||||
{
|
{
|
||||||
if (const FRigidBodyState* FoundState = Scene->GetStateFromReplicationCache(RootPrimComp, ServerFrame))
|
if (const FRigidBodyState* FoundState = Scene->GetStateFromReplicationCache(RootPrimComp, /*OUT*/ServerFrame))
|
||||||
{
|
{
|
||||||
RepMovement.FillFrom(*FoundState, this, Scene->ReplicationCache.ServerFrame);
|
if (RepMovement.ServerFrame != ServerFrame)
|
||||||
|
{
|
||||||
|
RepMovement.FillFrom(*FoundState, this, ServerFrame);
|
||||||
|
bWasRepMovementModified = true;
|
||||||
|
}
|
||||||
bFoundInCache = true;
|
bFoundInCache = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!bFoundInCache)
|
if (!bFoundInCache)
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "VRExpansionFunctionLibrary.h"
|
#include "VRExpansionFunctionLibrary.h"
|
||||||
#include "GripScripts/VRGripScriptBase.h"
|
#include "GripScripts/VRGripScriptBase.h"
|
||||||
#include "PhysicsEngine/PhysicsAsset.h" // Tmp until epic bug fixes skeletal welding
|
#include "PhysicsEngine/PhysicsAsset.h" // Tmp until epic bug fixes skeletal welding
|
||||||
|
#include "PhysicsEngine/SkeletalBodySetup.h"
|
||||||
#include "Net/UnrealNetwork.h"
|
#include "Net/UnrealNetwork.h"
|
||||||
#if WITH_PUSH_MODEL
|
#if WITH_PUSH_MODEL
|
||||||
#include "Net/Core/PushModel/PushModel.h"
|
#include "Net/Core/PushModel/PushModel.h"
|
||||||
|
|
|
@ -103,7 +103,7 @@ AGrippableStaticMeshActor::AGrippableStaticMeshActor(const FObjectInitializer& O
|
||||||
|
|
||||||
// Setting a minimum of every 3rd frame (VR 90fps) for replication consideration
|
// Setting a minimum of every 3rd frame (VR 90fps) for replication consideration
|
||||||
// Otherwise we will get some massive slow downs if the replication is allowed to hit the 2 per second minimum default
|
// Otherwise we will get some massive slow downs if the replication is allowed to hit the 2 per second minimum default
|
||||||
MinNetUpdateFrequency = 30.0f;
|
SetMinNetUpdateFrequency(30.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AGrippableStaticMeshActor::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty > & OutLifetimeProps) const
|
void AGrippableStaticMeshActor::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty > & OutLifetimeProps) const
|
||||||
|
@ -203,15 +203,25 @@ void AGrippableStaticMeshActor::GatherCurrentMovement()
|
||||||
bool bFoundInCache = false;
|
bool bFoundInCache = false;
|
||||||
|
|
||||||
UWorld* World = GetWorld();
|
UWorld* World = GetWorld();
|
||||||
|
|
||||||
|
const bool bShouldUsePhysicsReplicationCache = GetPhysicsReplicationMode() != EPhysicsReplicationMode::Default;
|
||||||
int ServerFrame = 0;
|
int ServerFrame = 0;
|
||||||
|
|
||||||
|
if (bShouldUsePhysicsReplicationCache)
|
||||||
|
{
|
||||||
if (FPhysScene_Chaos* Scene = static_cast<FPhysScene_Chaos*>(World->GetPhysicsScene()))
|
if (FPhysScene_Chaos* Scene = static_cast<FPhysScene_Chaos*>(World->GetPhysicsScene()))
|
||||||
{
|
{
|
||||||
if (const FRigidBodyState* FoundState = Scene->GetStateFromReplicationCache(RootPrimComp, ServerFrame))
|
if (const FRigidBodyState* FoundState = Scene->GetStateFromReplicationCache(RootPrimComp, /*OUT*/ServerFrame))
|
||||||
{
|
{
|
||||||
RepMovement.FillFrom(*FoundState, this, Scene->ReplicationCache.ServerFrame);
|
if (RepMovement.ServerFrame != ServerFrame)
|
||||||
|
{
|
||||||
|
RepMovement.FillFrom(*FoundState, this, ServerFrame);
|
||||||
|
bWasRepMovementModified = true;
|
||||||
|
}
|
||||||
bFoundInCache = true;
|
bFoundInCache = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!bFoundInCache)
|
if (!bFoundInCache)
|
||||||
{
|
{
|
||||||
|
@ -243,12 +253,6 @@ void AGrippableStaticMeshActor::GatherCurrentMovement()
|
||||||
|
|
||||||
// Technically, the values might have stayed the same, but we'll just assume they've changed.
|
// Technically, the values might have stayed the same, but we'll just assume they've changed.
|
||||||
bWasAttachmentModified = true;
|
bWasAttachmentModified = true;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Technically, the values might have stayed the same, but we'll just assume they've changed.
|
|
||||||
bWasRepMovementModified = true;
|
|
||||||
|
|
||||||
#if UE_WITH_IRIS
|
#if UE_WITH_IRIS
|
||||||
// If RepPhysics has changed value then notify the ReplicationSystem
|
// If RepPhysics has changed value then notify the ReplicationSystem
|
||||||
|
@ -258,6 +262,12 @@ void AGrippableStaticMeshActor::GatherCurrentMovement()
|
||||||
}
|
}
|
||||||
#endif // UE_WITH_IRIS
|
#endif // UE_WITH_IRIS
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Technically, the values might have stayed the same, but we'll just assume they've changed.
|
||||||
|
bWasRepMovementModified = true;
|
||||||
|
}
|
||||||
else if (RootComponent != nullptr)
|
else if (RootComponent != nullptr)
|
||||||
{
|
{
|
||||||
// If we are attached, don't replicate absolute position, use AttachmentReplication instead.
|
// If we are attached, don't replicate absolute position, use AttachmentReplication instead.
|
||||||
|
|
|
@ -272,7 +272,7 @@ void UVRDialComponent::OnGripRelease_Implementation(UGripMotionControllerCompone
|
||||||
float AngleOffsetCheck = FMath::Abs(FRotator::ClampAxis(CurRotBackEnd) - FRotator::ClampAxis(LastSnapAngle));
|
float AngleOffsetCheck = FMath::Abs(FRotator::ClampAxis(CurRotBackEnd) - FRotator::ClampAxis(LastSnapAngle));
|
||||||
float TargetSnap = FMath::RoundToFloat(FMath::GridSnap(CurRotBackEnd, SnapAngleIncrement));
|
float TargetSnap = FMath::RoundToFloat(FMath::GridSnap(CurRotBackEnd, SnapAngleIncrement));
|
||||||
|
|
||||||
if (FMath::Abs(FRotator::ClampAxis(CurRotBackEnd) - TargetSnap) <= FMath::Min(SnapAngleIncrement, SnapAngleThreshold))
|
if (FMath::Abs(/*FRotator::ClampAxis(*/CurRotBackEnd/*)*/ - TargetSnap) <= FMath::Min(SnapAngleIncrement, SnapAngleThreshold))
|
||||||
{
|
{
|
||||||
if (AngleOffsetCheck >= SnapAngleThreshold)//FMath::Min(SnapAngleIncrement, SnapAngleThreshold))
|
if (AngleOffsetCheck >= SnapAngleThreshold)//FMath::Min(SnapAngleIncrement, SnapAngleThreshold))
|
||||||
{
|
{
|
||||||
|
@ -592,7 +592,7 @@ void UVRDialComponent::AddDialAngle(float DialAngleDelta, bool bCallEvents, bool
|
||||||
float AngleOffsetCheck = FMath::Abs(FRotator::ClampAxis(CurRotBackEnd) - FRotator::ClampAxis(LastSnapAngle));
|
float AngleOffsetCheck = FMath::Abs(FRotator::ClampAxis(CurRotBackEnd) - FRotator::ClampAxis(LastSnapAngle));
|
||||||
float TargetSnap = FMath::RoundToFloat(FMath::GridSnap(CurRotBackEnd, SnapAngleIncrement));
|
float TargetSnap = FMath::RoundToFloat(FMath::GridSnap(CurRotBackEnd, SnapAngleIncrement));
|
||||||
|
|
||||||
if (FMath::Abs(FRotator::ClampAxis(CurRotBackEnd) - TargetSnap) <= FMath::Min(SnapAngleIncrement, SnapAngleThreshold))
|
if (FMath::Abs(/*FRotator::ClampAxis(*/CurRotBackEnd/*)*/ - TargetSnap) <= FMath::Min(SnapAngleIncrement, SnapAngleThreshold))
|
||||||
{
|
{
|
||||||
if (AngleOffsetCheck >= SnapAngleThreshold)//FMath::Min(SnapAngleIncrement, SnapAngleThreshold))
|
if (AngleOffsetCheck >= SnapAngleThreshold)//FMath::Min(SnapAngleIncrement, SnapAngleThreshold))
|
||||||
{
|
{
|
||||||
|
|
|
@ -810,7 +810,7 @@ FVector UVRSliderComponent::GetPerAxisSliderProgress()
|
||||||
CalculatedLocation = bSlideDistanceIsInParentSpace ? CalculatedLocation * InitialRelativeTransform.GetScale3D() : CalculatedLocation;
|
CalculatedLocation = bSlideDistanceIsInParentSpace ? CalculatedLocation * InitialRelativeTransform.GetScale3D() : CalculatedLocation;
|
||||||
|
|
||||||
// Should need the clamp normally, but if someone is manually setting locations it could go out of bounds
|
// Should need the clamp normally, but if someone is manually setting locations it could go out of bounds
|
||||||
FVector Progress;
|
FVector Progress = FVector::ZeroVector;
|
||||||
|
|
||||||
if (bUseLegacyLogic)
|
if (bUseLegacyLogic)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
//#include "Chaos/ParticleHandle.h"
|
//#include "Chaos/ParticleHandle.h"
|
||||||
#include "PhysicsEngine/PhysicsAsset.h"
|
#include "PhysicsEngine/PhysicsAsset.h"
|
||||||
#include "PhysicsEngine/PhysicsAsset.h"
|
#include "PhysicsEngine/SkeletalBodySetup.h"
|
||||||
#include "Physics/Experimental/PhysScene_Chaos.h"
|
#include "Physics/Experimental/PhysScene_Chaos.h"
|
||||||
#include "Chaos/KinematicGeometryParticles.h"
|
#include "Chaos/KinematicGeometryParticles.h"
|
||||||
#include "PhysicsProxy/SingleParticlePhysicsProxy.h"
|
#include "PhysicsProxy/SingleParticlePhysicsProxy.h"
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include "Net/UnrealNetwork.h"
|
#include "Net/UnrealNetwork.h"
|
||||||
#include "PhysicsReplication.h"
|
#include "PhysicsReplication.h"
|
||||||
#include "PhysicsEngine/PhysicsAsset.h"
|
#include "PhysicsEngine/PhysicsAsset.h"
|
||||||
|
#include "PhysicsEngine/BodySetup.h"
|
||||||
|
#include "PhysicsEngine/SkeletalBodySetup.h"
|
||||||
#if WITH_PUSH_MODEL
|
#if WITH_PUSH_MODEL
|
||||||
#include "Net/Core/PushModel/PushModel.h"
|
#include "Net/Core/PushModel/PushModel.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -269,7 +271,7 @@ void UInversePhysicsSkeletalMeshComponent::GetWeldedBodies(TArray<FBodyInstance*
|
||||||
OutWeldedBodies.Add(BI);
|
OutWeldedBodies.Add(BI);
|
||||||
if (PhysicsAsset)
|
if (PhysicsAsset)
|
||||||
{
|
{
|
||||||
if (UBodySetup* PhysicsAssetBodySetup = PhysicsAsset->SkeletalBodySetups[BodyIdx])
|
if (UBodySetup* PhysicsAssetBodySetup = PhysicsAsset->SkeletalBodySetups[BodyIdx].Get())
|
||||||
{
|
{
|
||||||
OutLabels.Add(PhysicsAssetBodySetup->BoneName);
|
OutLabels.Add(PhysicsAssetBodySetup->BoneName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ FORCEINLINE_DEBUGGABLE bool CheckIsTargetInSightPie(const FPerceptionListener& L
|
||||||
const FAISightTargetVR::FTargetId FAISightTargetVR::InvalidTargetId = FAISystem::InvalidUnsignedID;
|
const FAISightTargetVR::FTargetId FAISightTargetVR::InvalidTargetId = FAISystem::InvalidUnsignedID;
|
||||||
|
|
||||||
FAISightTargetVR::FAISightTargetVR(AActor* InTarget, FGenericTeamId InTeamId)
|
FAISightTargetVR::FAISightTargetVR(AActor* InTarget, FGenericTeamId InTeamId)
|
||||||
: Target(InTarget), SightTargetInterface(nullptr), TeamId(InTeamId)
|
: Target(InTarget), TeamId(InTeamId)
|
||||||
{
|
{
|
||||||
if (InTarget)
|
if (InTarget)
|
||||||
{
|
{
|
||||||
|
@ -587,7 +587,7 @@ UAISense_Sight::EVisibilityResult UAISense_Sight_VR::ComputeVisibility(UWorld* W
|
||||||
return UAISense_Sight::EVisibilityResult::NotVisible;
|
return UAISense_Sight::EVisibilityResult::NotVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Target.SightTargetInterface != nullptr)
|
if (IAISightTargetInterface* SightTargetInterface = Target.WeakSightTargetInterface.Get())
|
||||||
{
|
{
|
||||||
const bool bWasVisible = SightQuery.GetLastResult();
|
const bool bWasVisible = SightQuery.GetLastResult();
|
||||||
|
|
||||||
|
@ -620,7 +620,7 @@ UAISense_Sight::EVisibilityResult UAISense_Sight_VR::ComputeVisibility(UWorld* W
|
||||||
Context.IgnoreActor = ListenerActor;
|
Context.IgnoreActor = ListenerActor;
|
||||||
Context.bWasVisible = &bWasVisible;
|
Context.bWasVisible = &bWasVisible;
|
||||||
|
|
||||||
const UAISense_Sight::EVisibilityResult Result = Target.SightTargetInterface->CanBeSeenFrom(Context, OutSeenLocation, OutNumberOfLoSChecksPerformed, OutNumberOfAsyncLosCheckRequested, OutStimulusStrength, &SightQuery.UserData, &OnPendingCanBeSeenQueryProcessedDelegate);
|
const UAISense_Sight::EVisibilityResult Result = SightTargetInterface->CanBeSeenFrom(Context, OutSeenLocation, OutNumberOfLoSChecksPerformed, OutNumberOfAsyncLosCheckRequested, OutStimulusStrength, &SightQuery.UserData, &OnPendingCanBeSeenQueryProcessedDelegate);
|
||||||
if (Result == UAISense_Sight::EVisibilityResult::Pending)
|
if (Result == UAISense_Sight::EVisibilityResult::Pending)
|
||||||
{
|
{
|
||||||
// we need to clear the trace info value in order to avoid interfering with the engine processed asynchronous queries
|
// we need to clear the trace info value in order to avoid interfering with the engine processed asynchronous queries
|
||||||
|
@ -842,8 +842,6 @@ void UAISense_Sight_VR::UnregisterSource(AActor& SourceActor)
|
||||||
{
|
{
|
||||||
AActor* TargetActor = AsTarget.Target.Get();
|
AActor* TargetActor = AsTarget.Target.Get();
|
||||||
|
|
||||||
if (TargetActor)
|
|
||||||
{
|
|
||||||
// notify all interested observers that this source is no longer
|
// notify all interested observers that this source is no longer
|
||||||
// visible
|
// visible
|
||||||
AIPerception::FListenerMap& ListenersMap = *GetListeners();
|
AIPerception::FListenerMap& ListenersMap = *GetListeners();
|
||||||
|
@ -852,21 +850,18 @@ void UAISense_Sight_VR::UnregisterSource(AActor& SourceActor)
|
||||||
FAISightQueryVR* SightQuery = &SightQueries[QueryIndex];
|
FAISightQueryVR* SightQuery = &SightQueries[QueryIndex];
|
||||||
if (SightQuery->TargetId == AsTargetId)
|
if (SightQuery->TargetId == AsTargetId)
|
||||||
{
|
{
|
||||||
if (SightQuery->GetLastResult())
|
if (SightQuery->GetLastResult() && TargetActor)
|
||||||
{
|
{
|
||||||
FPerceptionListener& Listener = ListenersMap[SightQuery->ObserverId];
|
FPerceptionListener& Listener = ListenersMap[SightQuery->ObserverId];
|
||||||
ensure(Listener.Listener.IsValid());
|
ensure(Listener.Listener.IsValid());
|
||||||
|
|
||||||
Listener.RegisterStimulus(TargetActor, FAIStimulus(*this, 0.f, SightQuery->LastSeenLocation, Listener.CachedLocation, FAIStimulus::SensingFailed));
|
Listener.RegisterStimulus(TargetActor, FAIStimulus(*this, 0.f, SightQuery->LastSeenLocation, Listener.CachedLocation, FAIStimulus::SensingFailed));
|
||||||
}
|
}
|
||||||
|
|
||||||
SightQueries.RemoveAtSwap(QueryIndex, 1, EAllowShrinking::No);
|
SightQueries.RemoveAtSwap(QueryIndex, EAllowShrinking::No);
|
||||||
return EReverseForEachResult::Modified;
|
return EReverseForEachResult::Modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EReverseForEachResult::UnTouched;
|
return EReverseForEachResult::UnTouched;
|
||||||
};
|
};
|
||||||
|
|
||||||
ReverseForEach(SightQueriesInRange, RemoveQuery);
|
ReverseForEach(SightQueriesInRange, RemoveQuery);
|
||||||
if (ReverseForEach(SightQueriesOutOfRange, RemoveQuery) == EReverseForEachResult::Modified)
|
if (ReverseForEach(SightQueriesOutOfRange, RemoveQuery) == EReverseForEachResult::Modified)
|
||||||
{
|
{
|
||||||
|
@ -875,7 +870,6 @@ void UAISense_Sight_VR::UnregisterSource(AActor& SourceActor)
|
||||||
ReverseForEach(SightQueriesPending, RemoveQuery);
|
ReverseForEach(SightQueriesPending, RemoveQuery);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
bool UAISense_Sight_VR::RegisterTarget(AActor& TargetActor, const TFunction<void(FAISightQueryVR&)>& OnAddedFunc /*= nullptr*/)
|
bool UAISense_Sight_VR::RegisterTarget(AActor& TargetActor, const TFunction<void(FAISightQueryVR&)>& OnAddedFunc /*= nullptr*/)
|
||||||
{
|
{
|
||||||
|
@ -883,20 +877,24 @@ bool UAISense_Sight_VR::RegisterTarget(AActor& TargetActor, const TFunction<void
|
||||||
|
|
||||||
FAISightTargetVR* SightTarget = ObservedTargets.Find(TargetActor.GetUniqueID());
|
FAISightTargetVR* SightTarget = ObservedTargets.Find(TargetActor.GetUniqueID());
|
||||||
|
|
||||||
if (SightTarget != nullptr && SightTarget->GetTargetActor() != &TargetActor)
|
// Check if the target is recycled OR new
|
||||||
|
if (SightTarget == nullptr || SightTarget->GetTargetActor() != &TargetActor)
|
||||||
{
|
{
|
||||||
// this means given unique ID has already been recycled.
|
|
||||||
FAISightTargetVR NewSightTarget(&TargetActor);
|
FAISightTargetVR NewSightTarget(&TargetActor);
|
||||||
|
|
||||||
SightTarget = &(ObservedTargets.Add(NewSightTarget.TargetId, NewSightTarget));
|
SightTarget = &(ObservedTargets.Add(NewSightTarget.TargetId, NewSightTarget));
|
||||||
SightTarget->SightTargetInterface = Cast<IAISightTargetInterface>(&TargetActor);
|
// we're looking at components first and only if nothing is found we proceed to check
|
||||||
|
// if the TargetActor implements IAISightTargetInterface. The advantage of doing it in
|
||||||
|
// this order is that you can have components override the original Actor's implementation
|
||||||
|
if (IAISightTargetInterface* InterfaceComponent = TargetActor.FindComponentByInterface<IAISightTargetInterface>())
|
||||||
|
{
|
||||||
|
SightTarget->WeakSightTargetInterface = InterfaceComponent;
|
||||||
}
|
}
|
||||||
else if (SightTarget == nullptr)
|
else
|
||||||
{
|
{
|
||||||
FAISightTargetVR NewSightTarget(&TargetActor);
|
SightTarget->WeakSightTargetInterface = Cast<IAISightTargetInterface>(&TargetActor);
|
||||||
|
}
|
||||||
SightTarget = &(ObservedTargets.Add(NewSightTarget.TargetId, NewSightTarget));
|
|
||||||
SightTarget->SightTargetInterface = Cast<IAISightTargetInterface>(&TargetActor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set/update data
|
// set/update data
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "SceneManagement.h"
|
#include "SceneManagement.h"
|
||||||
#include "Components/SkeletalMeshComponent.h"
|
#include "Components/SkeletalMeshComponent.h"
|
||||||
#include "PhysicsEngine/PhysicsAsset.h"
|
#include "PhysicsEngine/PhysicsAsset.h"
|
||||||
|
#include "PhysicsEngine/ShapeElem.h"
|
||||||
#include "PhysicsEngine/ConstraintInstance.h"
|
#include "PhysicsEngine/ConstraintInstance.h"
|
||||||
#include "ReferenceSkeleton.h"
|
#include "ReferenceSkeleton.h"
|
||||||
#include "DrawDebugHelpers.h"
|
#include "DrawDebugHelpers.h"
|
||||||
|
|
|
@ -90,7 +90,7 @@ namespace
|
||||||
|
|
||||||
void RemoveWidget(UVRFullScreenUserWidget* InWidget)
|
void RemoveWidget(UVRFullScreenUserWidget* InWidget)
|
||||||
{
|
{
|
||||||
WidgetsToHide.RemoveSingleSwap(InWidget, false);
|
WidgetsToHide.RemoveSingleSwap(InWidget, EAllowShrinking::No);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1645,7 +1645,7 @@ bool RLE_Funcs::RLEEncodeBuffer(DataType* BufferToEncode, uint32 EncodeLength, T
|
||||||
|
|
||||||
// Resize the out array to fit compressed contents
|
// Resize the out array to fit compressed contents
|
||||||
uint32 Wrote = loc - EncodedLine->GetData();
|
uint32 Wrote = loc - EncodedLine->GetData();
|
||||||
EncodedLine->RemoveAt(Wrote, EncodedLine->Num() - Wrote, true);
|
EncodedLine->RemoveAt(Wrote, EncodedLine->Num() - Wrote, EAllowShrinking::Yes);
|
||||||
|
|
||||||
// If the compression performed worse than the original file size, throw the results array and use the original instead.
|
// If the compression performed worse than the original file size, throw the results array and use the original instead.
|
||||||
// This will almost never happen with voxels but can so should be accounted for.
|
// This will almost never happen with voxels but can so should be accounted for.
|
||||||
|
|
|
@ -434,7 +434,7 @@ void UReplicatedVRCameraComponent::TickComponent(float DeltaTime, enum ELevelTic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UReplicatedVRCameraComponent::HandleXRCamera()
|
void UReplicatedVRCameraComponent::HandleXRCamera(float DeltaTime)
|
||||||
{
|
{
|
||||||
bool bIsLocallyControlled = IsLocallyControlled();
|
bool bIsLocallyControlled = IsLocallyControlled();
|
||||||
|
|
||||||
|
@ -462,7 +462,7 @@ void UReplicatedVRCameraComponent::HandleXRCamera()
|
||||||
{
|
{
|
||||||
FQuat Orientation;
|
FQuat Orientation;
|
||||||
FVector Position;
|
FVector Position;
|
||||||
if (XRCamera->UpdatePlayerCamera(Orientation, Position))
|
if (XRCamera->UpdatePlayerCamera(Orientation, Position, DeltaTime))
|
||||||
{
|
{
|
||||||
if (HasTrackingParameters())
|
if (HasTrackingParameters())
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "Net/UnrealNetwork.h"
|
#include "Net/UnrealNetwork.h"
|
||||||
#include "XRMotionControllerBase.h"
|
#include "XRMotionControllerBase.h"
|
||||||
#include "NavFilters/NavigationQueryFilter.h"
|
#include "NavFilters/NavigationQueryFilter.h"
|
||||||
|
#include "Misc/EngineNetworkCustomVersion.h"
|
||||||
//#include "Runtime/Engine/Private/EnginePrivate.h"
|
//#include "Runtime/Engine/Private/EnginePrivate.h"
|
||||||
|
|
||||||
#if WITH_PUSH_MODEL
|
#if WITH_PUSH_MODEL
|
||||||
|
@ -142,7 +143,7 @@ AVRBaseCharacter::AVRBaseCharacter(const FObjectInitializer& ObjectInitializer)
|
||||||
|
|
||||||
// Setting a minimum of every frame for replication consideration (UT uses this value for characters and projectiles).
|
// Setting a minimum of every frame for replication consideration (UT uses this value for characters and projectiles).
|
||||||
// Otherwise we will get some massive slow downs if the replication is allowed to hit the 2 per second minimum default
|
// Otherwise we will get some massive slow downs if the replication is allowed to hit the 2 per second minimum default
|
||||||
MinNetUpdateFrequency = 100.0f;
|
SetMinNetUpdateFrequency(100.0f);
|
||||||
|
|
||||||
// This is for smooth turning, we have more of a use for this than FPS characters do
|
// This is for smooth turning, we have more of a use for this than FPS characters do
|
||||||
// Due to roll/pitch almost never being off 0 for VR the cost is just one byte so i'm fine defaulting it here
|
// Due to roll/pitch almost never being off 0 for VR the cost is just one byte so i'm fine defaulting it here
|
||||||
|
@ -434,6 +435,11 @@ void AVRBaseCharacter::OnRep_ReplicatedMovement()
|
||||||
ReppedMovement.Location = ReplicatedMovementVR.Location;
|
ReppedMovement.Location = ReplicatedMovementVR.Location;
|
||||||
ReppedMovement.Rotation = ReplicatedMovementVR.Rotation;
|
ReppedMovement.Rotation = ReplicatedMovementVR.Rotation;
|
||||||
|
|
||||||
|
ReppedMovement.ServerFrame = ReplicatedMovementVR.ServerFrame;
|
||||||
|
ReppedMovement.ServerPhysicsHandle = ReplicatedMovementVR.ServerPhysicsHandle;
|
||||||
|
ReppedMovement.bRepAcceleration = ReplicatedMovementVR.bRepAcceleration;
|
||||||
|
ReppedMovement.Acceleration = ReplicatedMovementVR.Acceleration;
|
||||||
|
|
||||||
Super::OnRep_ReplicatedMovement();
|
Super::OnRep_ReplicatedMovement();
|
||||||
|
|
||||||
if (!IsLocallyControlled())
|
if (!IsLocallyControlled())
|
||||||
|
@ -469,8 +475,14 @@ void AVRBaseCharacter::GatherCurrentMovement()
|
||||||
ReplicatedMovementVR.LinearVelocity = ReppedMovement.LinearVelocity;
|
ReplicatedMovementVR.LinearVelocity = ReppedMovement.LinearVelocity;
|
||||||
ReplicatedMovementVR.Location = ReppedMovement.Location;
|
ReplicatedMovementVR.Location = ReppedMovement.Location;
|
||||||
ReplicatedMovementVR.Rotation = ReppedMovement.Rotation;
|
ReplicatedMovementVR.Rotation = ReppedMovement.Rotation;
|
||||||
|
ReplicatedMovementVR.ServerFrame = ReppedMovement.ServerFrame;
|
||||||
|
ReplicatedMovementVR.ServerPhysicsHandle = ReppedMovement.ServerPhysicsHandle;
|
||||||
|
ReplicatedMovementVR.bRepAcceleration = ReppedMovement.bRepAcceleration;
|
||||||
|
ReplicatedMovementVR.Acceleration = ReppedMovement.Acceleration;
|
||||||
|
|
||||||
ReplicatedMovementVR.bJustTeleported = bFlagTeleported;
|
ReplicatedMovementVR.bJustTeleported = bFlagTeleported;
|
||||||
ReplicatedMovementVR.bJustTeleportedGrips = bFlagTeleportedGrips;
|
ReplicatedMovementVR.bJustTeleportedGrips = bFlagTeleportedGrips;
|
||||||
|
|
||||||
bFlagTeleported = false;
|
bFlagTeleported = false;
|
||||||
bFlagTeleportedGrips = false;
|
bFlagTeleportedGrips = false;
|
||||||
ReplicatedMovementVR.bPausedTracking = bTrackingPaused;
|
ReplicatedMovementVR.bPausedTracking = bTrackingPaused;
|
||||||
|
@ -1001,7 +1013,7 @@ FVector AVRBaseCharacter::SetActorLocationAndRotationVR(FVector NewLoc, FRotator
|
||||||
FVector AVRBaseCharacter::SetActorLocationVR(FVector NewLoc, bool bTeleport, bool bSetCapsuleLocation)
|
FVector AVRBaseCharacter::SetActorLocationVR(FVector NewLoc, bool bTeleport, bool bSetCapsuleLocation)
|
||||||
{
|
{
|
||||||
FVector NewLocation;
|
FVector NewLocation;
|
||||||
FRotator NewRotation;
|
//FRotator NewRotation;
|
||||||
FVector PivotOffsetVal = (bSetCapsuleLocation ? GetVRLocation_Inline() : GetProjectedVRLocation()) - GetActorLocation();
|
FVector PivotOffsetVal = (bSetCapsuleLocation ? GetVRLocation_Inline() : GetProjectedVRLocation()) - GetActorLocation();
|
||||||
PivotOffsetVal.Z = 0.0f;
|
PivotOffsetVal.Z = 0.0f;
|
||||||
|
|
||||||
|
@ -1244,3 +1256,102 @@ void AVRBaseCharacter::SetVRReplicateCapsuleHeight(bool bNewVRReplicateCapsuleHe
|
||||||
MARK_PROPERTY_DIRTY_FROM_NAME(AVRBaseCharacter, VRReplicateCapsuleHeight, this);
|
MARK_PROPERTY_DIRTY_FROM_NAME(AVRBaseCharacter, VRReplicateCapsuleHeight, this);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FRepMovementVRCharacter::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
|
||||||
|
{
|
||||||
|
Ar.UsingCustomVersion(FEngineNetworkCustomVersion::Guid);
|
||||||
|
|
||||||
|
FRepMovement BaseSettings = Owner ? Owner->GetReplicatedMovement() : FRepMovement();
|
||||||
|
|
||||||
|
// pack bitfield with flags
|
||||||
|
const bool bServerFrameAndHandleSupported = Ar.EngineNetVer() >= FEngineNetworkCustomVersion::RepMoveServerFrameAndHandle && Ar.EngineNetVer() != FEngineNetworkCustomVersion::Ver21AndViewPitchOnly_DONOTUSE;
|
||||||
|
uint8 Flags = (bSimulatedPhysicSleep << 0) | (bRepPhysics << 1) | (bJustTeleported << 2) | (bJustTeleportedGrips << 3) | (bPausedTracking << 4);
|
||||||
|
Ar.SerializeBits(&Flags, 5);
|
||||||
|
bSimulatedPhysicSleep = (Flags & (1 << 0)) ? 1 : 0;
|
||||||
|
bRepPhysics = (Flags & (1 << 1)) ? 1 : 0;
|
||||||
|
const bool bRepServerFrame = (Flags & (1 << 2) && bServerFrameAndHandleSupported) ? 1 : 0;
|
||||||
|
const bool bRepServerHandle = (Flags & (1 << 3) && bServerFrameAndHandleSupported) ? 1 : 0;
|
||||||
|
|
||||||
|
bJustTeleported = (Flags & (1 << 2)) ? 1 : 0;
|
||||||
|
bJustTeleportedGrips = (Flags & (1 << 3)) ? 1 : 0;
|
||||||
|
bPausedTracking = (Flags & (1 << 4)) ? 1 : 0;
|
||||||
|
|
||||||
|
bOutSuccess = true;
|
||||||
|
|
||||||
|
if (bPausedTracking)
|
||||||
|
{
|
||||||
|
bOutSuccess &= PausedTrackingLoc.NetSerialize(Ar, Map, bOutSuccess);
|
||||||
|
|
||||||
|
uint16 Yaw = 0;
|
||||||
|
if (Ar.IsSaving())
|
||||||
|
{
|
||||||
|
Yaw = FRotator::CompressAxisToShort(PausedTrackingRot);
|
||||||
|
Ar << Yaw;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Ar << Yaw;
|
||||||
|
PausedTrackingRot = Yaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// update location, rotation, linear velocity
|
||||||
|
bOutSuccess &= SerializeQuantizedVector(Ar, Location, BaseSettings.LocationQuantizationLevel);
|
||||||
|
|
||||||
|
switch (BaseSettings.RotationQuantizationLevel)
|
||||||
|
{
|
||||||
|
case ERotatorQuantization::ByteComponents:
|
||||||
|
{
|
||||||
|
Rotation.SerializeCompressed(Ar);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ERotatorQuantization::ShortComponents:
|
||||||
|
{
|
||||||
|
Rotation.SerializeCompressedShort(Ar);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bOutSuccess &= SerializeQuantizedVector(Ar, LinearVelocity, BaseSettings.VelocityQuantizationLevel);
|
||||||
|
|
||||||
|
// update angular velocity if required
|
||||||
|
if (bRepPhysics)
|
||||||
|
{
|
||||||
|
bOutSuccess &= SerializeQuantizedVector(Ar, AngularVelocity, BaseSettings.VelocityQuantizationLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bRepServerFrame)
|
||||||
|
{
|
||||||
|
uint32 uServerFrame = (uint32)ServerFrame;
|
||||||
|
Ar.SerializeIntPacked(uServerFrame);
|
||||||
|
ServerFrame = (int32)uServerFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bRepServerHandle)
|
||||||
|
{
|
||||||
|
uint32 uServerPhysicsHandle = (uint32)ServerPhysicsHandle;
|
||||||
|
Ar.SerializeIntPacked(uServerPhysicsHandle);
|
||||||
|
ServerPhysicsHandle = (int32)uServerPhysicsHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Ar.EngineNetVer() >= FEngineNetworkCustomVersion::RepMoveOptionalAcceleration)
|
||||||
|
{
|
||||||
|
uint8 AccelFlags = (bRepAcceleration << 0);
|
||||||
|
Ar.SerializeBits(&AccelFlags, 1);
|
||||||
|
bRepAcceleration = (AccelFlags & (1 << 0)) ? 1 : 0;
|
||||||
|
|
||||||
|
if (bRepAcceleration)
|
||||||
|
{
|
||||||
|
// Note that we're using the same quantization as Velocity, since the units are commonly on the same order
|
||||||
|
bOutSuccess &= SerializeQuantizedVector(Ar, Acceleration, VelocityQuantizationLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Ar.IsLoading())
|
||||||
|
{
|
||||||
|
bRepAcceleration = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -489,14 +489,32 @@ void UVRBaseCharacterMovementComponent::EndPushBackNotification()
|
||||||
|
|
||||||
FVector UVRBaseCharacterMovementComponent::GetActorFeetLocationVR() const
|
FVector UVRBaseCharacterMovementComponent::GetActorFeetLocationVR() const
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const UCapsuleComponent* const CapsuleComponent = CharacterOwner ? CharacterOwner->GetCapsuleComponent() : Cast<UCapsuleComponent>(UpdatedComponent);
|
||||||
|
if (CapsuleComponent)
|
||||||
|
{
|
||||||
|
const float HalfHeight = CapsuleComponent->GetScaledCapsuleHalfHeight();
|
||||||
if (AVRBaseCharacter* BaseCharacter = Cast<AVRBaseCharacter>(GetCharacterOwner()))
|
if (AVRBaseCharacter* BaseCharacter = Cast<AVRBaseCharacter>(GetCharacterOwner()))
|
||||||
|
{
|
||||||
|
return BaseCharacter->OffsetComponentToWorld.GetLocation() + HalfHeight * GetGravityDirection();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return UpdatedComponent->GetComponentLocation() + HalfHeight * GetGravityDirection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Super::GetActorFeetLocation();
|
||||||
|
|
||||||
|
|
||||||
|
/*if (AVRBaseCharacter* BaseCharacter = Cast<AVRBaseCharacter>(GetCharacterOwner()))
|
||||||
{
|
{
|
||||||
return UpdatedComponent ? (BaseCharacter->OffsetComponentToWorld.GetLocation() - FVector(0, 0, UpdatedComponent->Bounds.BoxExtent.Z)) : FNavigationSystem::InvalidLocation;
|
return UpdatedComponent ? (BaseCharacter->OffsetComponentToWorld.GetLocation() - FVector(0, 0, UpdatedComponent->Bounds.BoxExtent.Z)) : FNavigationSystem::InvalidLocation;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return UpdatedComponent ? (UpdatedComponent->GetComponentLocation() - FVector(0, 0, UpdatedComponent->Bounds.BoxExtent.Z)) : FNavigationSystem::InvalidLocation;
|
return UpdatedComponent ? (UpdatedComponent->GetComponentLocation() - FVector(0, 0, UpdatedComponent->Bounds.BoxExtent.Z)) : FNavigationSystem::InvalidLocation;
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void UVRBaseCharacterMovementComponent::OnMoveCompleted(FAIRequestID RequestID, const FPathFollowingResult& Result)
|
void UVRBaseCharacterMovementComponent::OnMoveCompleted(FAIRequestID RequestID, const FPathFollowingResult& Result)
|
||||||
|
@ -533,7 +551,8 @@ bool UVRBaseCharacterMovementComponent::FloorSweepTest(
|
||||||
const FCollisionShape BoxShape = FCollisionShape::MakeBox(FVector(CapsuleRadius * 0.707f, CapsuleRadius * 0.707f, CapsuleHeight));
|
const FCollisionShape BoxShape = FCollisionShape::MakeBox(FVector(CapsuleRadius * 0.707f, CapsuleRadius * 0.707f, CapsuleHeight));
|
||||||
|
|
||||||
// First test with the box rotated so the corners are along the major axes (ie rotated 45 degrees).
|
// First test with the box rotated so the corners are along the major axes (ie rotated 45 degrees).
|
||||||
bBlockingHit = GetWorld()->SweepSingleByChannel(OutHit, Start, End, FQuat(RotateGravityToWorld(FVector(0.f, 0.f, -1.f)), UE_PI * 0.25f), TraceChannel, BoxShape, Params, ResponseParam);
|
//bBlockingHit = GetWorld()->SweepSingleByChannel(OutHit, Start, End, FQuat(RotateGravityToWorld(FVector(0.f, 0.f, -1.f)), UE_PI * 0.25f), TraceChannel, BoxShape, Params, ResponseParam);
|
||||||
|
bBlockingHit = GetWorld()->SweepSingleByChannel(OutHit, Start, End, FQuat(GetGravityDirection(), UE_PI * 0.25f), TraceChannel, BoxShape, Params, ResponseParam);
|
||||||
|
|
||||||
if (!bBlockingHit)
|
if (!bBlockingHit)
|
||||||
{
|
{
|
||||||
|
@ -558,8 +577,8 @@ void UVRBaseCharacterMovementComponent::ComputeFloorDist(const FVector& CapsuleL
|
||||||
if (DownwardSweepResult != NULL && DownwardSweepResult->IsValidBlockingHit())
|
if (DownwardSweepResult != NULL && DownwardSweepResult->IsValidBlockingHit())
|
||||||
{
|
{
|
||||||
// Only if the supplied sweep was vertical and downward.
|
// Only if the supplied sweep was vertical and downward.
|
||||||
const bool bIsDownward = RotateWorldToGravity(DownwardSweepResult->TraceStart - DownwardSweepResult->TraceEnd).Z > 0;
|
const bool bIsDownward = GetGravitySpaceZ(DownwardSweepResult->TraceStart - DownwardSweepResult->TraceEnd) > 0;
|
||||||
const bool bIsVertical = RotateWorldToGravity(DownwardSweepResult->TraceStart - DownwardSweepResult->TraceEnd).SizeSquared2D() <= UE_KINDA_SMALL_NUMBER;
|
const bool bIsVertical = ProjectToGravityFloor(DownwardSweepResult->TraceStart - DownwardSweepResult->TraceEnd).SizeSquared() <= UE_KINDA_SMALL_NUMBER;
|
||||||
if (bIsDownward && bIsVertical)
|
if (bIsDownward && bIsVertical)
|
||||||
{
|
{
|
||||||
// Reject hits that are barely on the cusp of the radius of the capsule
|
// Reject hits that are barely on the cusp of the radius of the capsule
|
||||||
|
@ -569,7 +588,7 @@ void UVRBaseCharacterMovementComponent::ComputeFloorDist(const FVector& CapsuleL
|
||||||
bSkipSweep = true;
|
bSkipSweep = true;
|
||||||
|
|
||||||
const bool bIsWalkable = IsWalkable(*DownwardSweepResult);
|
const bool bIsWalkable = IsWalkable(*DownwardSweepResult);
|
||||||
const float FloorDist = RotateWorldToGravity(CapsuleLocation - DownwardSweepResult->Location).Z;
|
const float FloorDist = GetGravitySpaceZ(CapsuleLocation - DownwardSweepResult->Location);
|
||||||
OutFloorResult.SetFromSweep(*DownwardSweepResult, FloorDist, bIsWalkable);
|
OutFloorResult.SetFromSweep(*DownwardSweepResult, FloorDist, bIsWalkable);
|
||||||
|
|
||||||
if (bIsWalkable)
|
if (bIsWalkable)
|
||||||
|
@ -610,7 +629,7 @@ void UVRBaseCharacterMovementComponent::ComputeFloorDist(const FVector& CapsuleL
|
||||||
FCollisionShape CapsuleShape = FCollisionShape::MakeCapsule(SweepRadius, PawnHalfHeight - ShrinkHeight);
|
FCollisionShape CapsuleShape = FCollisionShape::MakeCapsule(SweepRadius, PawnHalfHeight - ShrinkHeight);
|
||||||
|
|
||||||
FHitResult Hit(1.f);
|
FHitResult Hit(1.f);
|
||||||
bBlockingHit = FloorSweepTest(Hit, CapsuleLocation, CapsuleLocation + RotateGravityToWorld(FVector(0.f, 0.f, -TraceDist)), CollisionChannel, CapsuleShape, QueryParams, ResponseParam);
|
bBlockingHit = FloorSweepTest(Hit, CapsuleLocation, CapsuleLocation + TraceDist * GetGravityDirection(), CollisionChannel, CapsuleShape, QueryParams, ResponseParam);
|
||||||
|
|
||||||
if (bBlockingHit)
|
if (bBlockingHit)
|
||||||
{
|
{
|
||||||
|
@ -628,7 +647,7 @@ void UVRBaseCharacterMovementComponent::ComputeFloorDist(const FVector& CapsuleL
|
||||||
CapsuleShape.Capsule.HalfHeight = FMath::Max(PawnHalfHeight - ShrinkHeight, CapsuleShape.Capsule.Radius);
|
CapsuleShape.Capsule.HalfHeight = FMath::Max(PawnHalfHeight - ShrinkHeight, CapsuleShape.Capsule.Radius);
|
||||||
Hit.Reset(1.f, false);
|
Hit.Reset(1.f, false);
|
||||||
|
|
||||||
bBlockingHit = FloorSweepTest(Hit, CapsuleLocation, CapsuleLocation + RotateGravityToWorld(FVector(0.f, 0.f, -TraceDist)), CollisionChannel, CapsuleShape, QueryParams, ResponseParam);
|
bBlockingHit = FloorSweepTest(Hit, CapsuleLocation, CapsuleLocation + TraceDist * GetGravityDirection(), CollisionChannel, CapsuleShape, QueryParams, ResponseParam);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,7 +683,7 @@ void UVRBaseCharacterMovementComponent::ComputeFloorDist(const FVector& CapsuleL
|
||||||
const float ShrinkHeight = PawnHalfHeight;
|
const float ShrinkHeight = PawnHalfHeight;
|
||||||
const FVector LineTraceStart = CapsuleLocation;
|
const FVector LineTraceStart = CapsuleLocation;
|
||||||
const float TraceDist = LineDistance + ShrinkHeight;
|
const float TraceDist = LineDistance + ShrinkHeight;
|
||||||
const FVector Down = RotateGravityToWorld(FVector(0.f, 0.f, -TraceDist));
|
const FVector Down = TraceDist * GetGravityDirection();
|
||||||
QueryParams.TraceTag = SCENE_QUERY_STAT_NAME_ONLY(FloorLineTrace);
|
QueryParams.TraceTag = SCENE_QUERY_STAT_NAME_ONLY(FloorLineTrace);
|
||||||
|
|
||||||
FHitResult Hit(1.f);
|
FHitResult Hit(1.f);
|
||||||
|
@ -703,31 +722,32 @@ float UVRBaseCharacterMovementComponent::SlideAlongSurface(const FVector& Delta,
|
||||||
return 0.f;
|
return 0.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
FVector Normal(RotateWorldToGravity(InNormal));
|
FVector Normal(InNormal);
|
||||||
|
const FVector::FReal NormalZ = GetGravitySpaceZ(Normal);
|
||||||
if (IsMovingOnGround())
|
if (IsMovingOnGround())
|
||||||
{
|
{
|
||||||
// We don't want to be pushed up an unwalkable surface.
|
// We don't want to be pushed up an unwalkable surface.
|
||||||
if (Normal.Z > 0.f)
|
if (NormalZ > 0.f)
|
||||||
{
|
{
|
||||||
if (!IsWalkable(Hit))
|
if (!IsWalkable(Hit))
|
||||||
{
|
{
|
||||||
Normal = Normal.GetSafeNormal2D();
|
Normal = ProjectToGravityFloor(Normal).GetSafeNormal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Normal.Z < -UE_KINDA_SMALL_NUMBER)
|
else if (NormalZ < -UE_KINDA_SMALL_NUMBER)
|
||||||
{
|
{
|
||||||
// Don't push down into the floor when the impact is on the upper portion of the capsule.
|
// Don't push down into the floor when the impact is on the upper portion of the capsule.
|
||||||
if (CurrentFloor.FloorDist < MIN_FLOOR_DIST && CurrentFloor.bBlockingHit)
|
if (CurrentFloor.FloorDist < MIN_FLOOR_DIST && CurrentFloor.bBlockingHit)
|
||||||
{
|
{
|
||||||
const FVector FloorNormal = RotateWorldToGravity(CurrentFloor.HitResult.Normal);
|
const FVector FloorNormal = CurrentFloor.HitResult.Normal;
|
||||||
const bool bFloorOpposedToMovement = (RotateWorldToGravity(Delta) | FloorNormal) < 0.f && (FloorNormal.Z < 1.f - UE_DELTA);
|
const bool bFloorOpposedToMovement = (Delta | FloorNormal) < 0.f && (GetGravitySpaceZ(FloorNormal) < 1.f - UE_DELTA);
|
||||||
|
|
||||||
if (bFloorOpposedToMovement)
|
if (bFloorOpposedToMovement)
|
||||||
{
|
{
|
||||||
Normal = FloorNormal;
|
Normal = FloorNormal;
|
||||||
}
|
}
|
||||||
|
|
||||||
Normal = Normal.GetSafeNormal2D();
|
Normal = ProjectToGravityFloor(Normal).GetSafeNormal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -744,9 +764,9 @@ float UVRBaseCharacterMovementComponent::SlideAlongSurface(const FVector& Delta,
|
||||||
// that we have already validated the floor normal.
|
// that we have already validated the floor normal.
|
||||||
// Otherwise just pass in as normal, either way skip the parents implementation as we are doing it now.
|
// Otherwise just pass in as normal, either way skip the parents implementation as we are doing it now.
|
||||||
if (IsMovingOnGround() || (MovementMode == MOVE_Custom && CustomMovementMode == (uint8)EVRCustomMovementMode::VRMOVE_Climbing))
|
if (IsMovingOnGround() || (MovementMode == MOVE_Custom && CustomMovementMode == (uint8)EVRCustomMovementMode::VRMOVE_Climbing))
|
||||||
return Super::Super::SlideAlongSurface(Delta * VRWallSlideScaler, Time, RotateGravityToWorld(Normal), Hit, bHandleImpact);
|
return Super::Super::SlideAlongSurface(Delta * VRWallSlideScaler, Time, Normal, Hit, bHandleImpact);
|
||||||
else
|
else
|
||||||
return Super::Super::SlideAlongSurface(Delta, Time, RotateGravityToWorld(Normal), Hit, bHandleImpact);
|
return Super::Super::SlideAlongSurface(Delta, Time, Normal, Hit, bHandleImpact);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*void UVRBaseCharacterMovementComponent::SetCrouchedHalfHeight(float NewCrouchedHalfHeight)
|
/*void UVRBaseCharacterMovementComponent::SetCrouchedHalfHeight(float NewCrouchedHalfHeight)
|
||||||
|
@ -2019,12 +2039,12 @@ void UVRBaseCharacterMovementComponent::SmoothCorrection(const FVector& OldLocat
|
||||||
|
|
||||||
// The mesh doesn't move, but the capsule does so we have a new offset.
|
// The mesh doesn't move, but the capsule does so we have a new offset.
|
||||||
FVector NewToOldVector = (OldWorldLocation - NewWorldLocation);
|
FVector NewToOldVector = (OldWorldLocation - NewWorldLocation);
|
||||||
if (bIsNavWalkingOnServer && FMath::Abs(NewToOldVector.Z) < NavWalkingFloorDistTolerance)
|
if (bIsNavWalkingOnServer && FMath::Abs(GetGravitySpaceZ(NewToOldVector)) < NavWalkingFloorDistTolerance)
|
||||||
{
|
{
|
||||||
// ignore smoothing on Z axis
|
// ignore smoothing on Z axis
|
||||||
// don't modify new location (local simulation result), since it's probably more accurate than server data
|
// don't modify new location (local simulation result), since it's probably more accurate than server data
|
||||||
// and shouldn't matter as long as difference is relatively small
|
// and shouldn't matter as long as difference is relatively small
|
||||||
NewToOldVector.Z = 0;
|
NewToOldVector = ProjectToGravityFloor(NewToOldVector);
|
||||||
}
|
}
|
||||||
|
|
||||||
const float DistSq = NewToOldVector.SizeSquared();
|
const float DistSq = NewToOldVector.SizeSquared();
|
||||||
|
|
|
@ -173,7 +173,7 @@ void UVRCharacterMovementComponent::Crouch(bool bClientSimulation)
|
||||||
else
|
else
|
||||||
capLocation = UpdatedComponent->GetComponentLocation();
|
capLocation = UpdatedComponent->GetComponentLocation();
|
||||||
|
|
||||||
const bool bEncroached = GetWorld()->OverlapBlockingTestByChannel(capLocation - FVector(0.f, 0.f, ScaledHalfHeightAdjust), FQuat::Identity,
|
const bool bEncroached = GetWorld()->OverlapBlockingTestByChannel(capLocation - (ScaledHalfHeightAdjust * GetGravityDirection()), FQuat::Identity,
|
||||||
UpdatedComponent->GetCollisionObjectType(), GetPawnCapsuleCollisionShape(SHRINK_None), CapsuleParams, ResponseParam);
|
UpdatedComponent->GetCollisionObjectType(), GetPawnCapsuleCollisionShape(SHRINK_None), CapsuleParams, ResponseParam);
|
||||||
|
|
||||||
// If encroached, cancel
|
// If encroached, cancel
|
||||||
|
@ -192,7 +192,7 @@ void UVRCharacterMovementComponent::Crouch(bool bClientSimulation)
|
||||||
if (bCrouchMaintainsBaseLocation)
|
if (bCrouchMaintainsBaseLocation)
|
||||||
{
|
{
|
||||||
// Intentionally not using MoveUpdatedComponent, where a horizontal plane constraint would prevent the base of the capsule from staying at the same spot.
|
// Intentionally not using MoveUpdatedComponent, where a horizontal plane constraint would prevent the base of the capsule from staying at the same spot.
|
||||||
//UpdatedComponent->MoveComponent(FVector(0.f, 0.f, -ScaledHalfHeightAdjust), UpdatedComponent->GetComponentQuat(), true, nullptr, EMoveComponentFlags::MOVECOMP_NoFlags, ETeleportType::TeleportPhysics);
|
//UpdatedComponent->MoveComponent(ScaledHalfHeightAdjust * GetGravityDirection(), UpdatedComponent->GetComponentQuat(), true, nullptr, EMoveComponentFlags::MOVECOMP_NoFlags, ETeleportType::TeleportPhysics);
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterOwner->bIsCrouched = true;
|
CharacterOwner->bIsCrouched = true;
|
||||||
|
@ -219,7 +219,7 @@ void UVRCharacterMovementComponent::Crouch(bool bClientSimulation)
|
||||||
|
|
||||||
if (ClientData)
|
if (ClientData)
|
||||||
{
|
{
|
||||||
ClientData->MeshTranslationOffset -= FVector(0.f, 0.f, MeshAdjust);
|
ClientData->MeshTranslationOffset -= MeshAdjust * -GetGravityDirection();
|
||||||
ClientData->OriginalMeshTranslationOffset = ClientData->MeshTranslationOffset;
|
ClientData->OriginalMeshTranslationOffset = ClientData->MeshTranslationOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -280,7 +280,7 @@ void UVRCharacterMovementComponent::UnCrouch(bool bClientSimulation)
|
||||||
if (!bCrouchMaintainsBaseLocation)
|
if (!bCrouchMaintainsBaseLocation)
|
||||||
{
|
{
|
||||||
// Expand in place
|
// Expand in place
|
||||||
bEncroached = MyWorld->OverlapBlockingTestByChannel(PawnLocation, FQuat::Identity, CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
|
bEncroached = MyWorld->OverlapBlockingTestByChannel(PawnLocation, GetWorldToGravityTransform(), CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
|
||||||
|
|
||||||
if (bEncroached)
|
if (bEncroached)
|
||||||
{
|
{
|
||||||
|
@ -292,11 +292,11 @@ void UVRCharacterMovementComponent::UnCrouch(bool bClientSimulation)
|
||||||
CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnRadius, PawnHalfHeight);
|
CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnRadius, PawnHalfHeight);
|
||||||
const float ShrinkHalfHeight = PawnHalfHeight - PawnRadius;
|
const float ShrinkHalfHeight = PawnHalfHeight - PawnRadius;
|
||||||
const float TraceDist = PawnHalfHeight - ShrinkHalfHeight;
|
const float TraceDist = PawnHalfHeight - ShrinkHalfHeight;
|
||||||
const FVector Down = FVector(0.f, 0.f, -TraceDist);
|
const FVector Down = TraceDist * GetGravityDirection();
|
||||||
|
|
||||||
FHitResult Hit(1.f);
|
FHitResult Hit(1.f);
|
||||||
const FCollisionShape ShortCapsuleShape = GetPawnCapsuleCollisionShape(SHRINK_HeightCustom, ShrinkHalfHeight);
|
const FCollisionShape ShortCapsuleShape = GetPawnCapsuleCollisionShape(SHRINK_HeightCustom, ShrinkHalfHeight);
|
||||||
const bool bBlockingHit = MyWorld->SweepSingleByChannel(Hit, PawnLocation, PawnLocation + Down, FQuat::Identity, CollisionChannel, ShortCapsuleShape, CapsuleParams);
|
const bool bBlockingHit = MyWorld->SweepSingleByChannel(Hit, PawnLocation, PawnLocation + Down, GetWorldToGravityTransform(), CollisionChannel, ShortCapsuleShape, CapsuleParams);
|
||||||
if (Hit.bStartPenetrating)
|
if (Hit.bStartPenetrating)
|
||||||
{
|
{
|
||||||
bEncroached = true;
|
bEncroached = true;
|
||||||
|
@ -305,8 +305,9 @@ void UVRCharacterMovementComponent::UnCrouch(bool bClientSimulation)
|
||||||
{
|
{
|
||||||
// Compute where the base of the sweep ended up, and see if we can stand there
|
// Compute where the base of the sweep ended up, and see if we can stand there
|
||||||
const float DistanceToBase = (Hit.Time * TraceDist) + ShortCapsuleShape.Capsule.HalfHeight;
|
const float DistanceToBase = (Hit.Time * TraceDist) + ShortCapsuleShape.Capsule.HalfHeight;
|
||||||
const FVector NewLoc = FVector(PawnLocation.X, PawnLocation.Y, PawnLocation.Z - DistanceToBase + StandingCapsuleShape.Capsule.HalfHeight + SweepInflation + MIN_FLOOR_DIST / 2.f);
|
const FVector Adjustment = (-DistanceToBase + StandingCapsuleShape.Capsule.HalfHeight + SweepInflation + MIN_FLOOR_DIST / 2.f) * -GetGravityDirection();
|
||||||
bEncroached = MyWorld->OverlapBlockingTestByChannel(NewLoc, FQuat::Identity, CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
|
const FVector NewLoc = PawnLocation + Adjustment;
|
||||||
|
bEncroached = MyWorld->OverlapBlockingTestByChannel(NewLoc, GetWorldToGravityTransform(), CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
|
||||||
if (!bEncroached)
|
if (!bEncroached)
|
||||||
{
|
{
|
||||||
// Intentionally not using MoveUpdatedComponent, where a horizontal plane constraint would prevent the base of the capsule from staying at the same spot.
|
// Intentionally not using MoveUpdatedComponent, where a horizontal plane constraint would prevent the base of the capsule from staying at the same spot.
|
||||||
|
@ -319,8 +320,8 @@ void UVRCharacterMovementComponent::UnCrouch(bool bClientSimulation)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Expand while keeping base location the same.
|
// Expand while keeping base location the same.
|
||||||
FVector StandingLocation = PawnLocation + FVector(0.f, 0.f, StandingCapsuleShape.GetCapsuleHalfHeight() - CurrentCrouchedHalfHeight);
|
FVector StandingLocation = PawnLocation + (StandingCapsuleShape.GetCapsuleHalfHeight() - CurrentCrouchedHalfHeight) * -GetGravityDirection();
|
||||||
bEncroached = MyWorld->OverlapBlockingTestByChannel(StandingLocation, FQuat::Identity, CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
|
bEncroached = MyWorld->OverlapBlockingTestByChannel(StandingLocation, GetWorldToGravityTransform(), CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
|
||||||
|
|
||||||
if (bEncroached)
|
if (bEncroached)
|
||||||
{
|
{
|
||||||
|
@ -330,8 +331,8 @@ void UVRCharacterMovementComponent::UnCrouch(bool bClientSimulation)
|
||||||
const float MinFloorDist = UE_KINDA_SMALL_NUMBER * 10.f;
|
const float MinFloorDist = UE_KINDA_SMALL_NUMBER * 10.f;
|
||||||
if (CurrentFloor.bBlockingHit && CurrentFloor.FloorDist > MinFloorDist)
|
if (CurrentFloor.bBlockingHit && CurrentFloor.FloorDist > MinFloorDist)
|
||||||
{
|
{
|
||||||
StandingLocation.Z -= CurrentFloor.FloorDist - MinFloorDist;
|
StandingLocation -= (CurrentFloor.FloorDist - MinFloorDist) * -GetGravityDirection();
|
||||||
bEncroached = MyWorld->OverlapBlockingTestByChannel(StandingLocation, FQuat::Identity, CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
|
bEncroached = MyWorld->OverlapBlockingTestByChannel(StandingLocation, GetWorldToGravityTransform(), CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -375,7 +376,7 @@ void UVRCharacterMovementComponent::UnCrouch(bool bClientSimulation)
|
||||||
|
|
||||||
if (ClientData)
|
if (ClientData)
|
||||||
{
|
{
|
||||||
ClientData->MeshTranslationOffset += FVector(0.f, 0.f, MeshAdjust);
|
ClientData->MeshTranslationOffset += MeshAdjust * -GetGravityDirection();
|
||||||
ClientData->OriginalMeshTranslationOffset = ClientData->MeshTranslationOffset;
|
ClientData->OriginalMeshTranslationOffset = ClientData->MeshTranslationOffset;
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
@ -856,7 +857,7 @@ bool UVRCharacterMovementComponent::ShouldCheckForValidLandingSpot(float DeltaTi
|
||||||
{
|
{
|
||||||
// See if we hit an edge of a surface on the lower portion of the capsule.
|
// See if we hit an edge of a surface on the lower portion of the capsule.
|
||||||
// In this case the normal will not equal the impact normal, and a downward sweep may find a walkable surface on top of the edge.
|
// In this case the normal will not equal the impact normal, and a downward sweep may find a walkable surface on top of the edge.
|
||||||
if (Hit.Normal.Z > UE_KINDA_SMALL_NUMBER && !Hit.Normal.Equals(Hit.ImpactNormal))
|
if (GetGravitySpaceZ(Hit.Normal) > UE_KINDA_SMALL_NUMBER && !Hit.Normal.Equals(Hit.ImpactNormal))
|
||||||
{
|
{
|
||||||
FVector PawnLocation = UpdatedComponent->GetComponentLocation();
|
FVector PawnLocation = UpdatedComponent->GetComponentLocation();
|
||||||
if (VRRootCapsule)
|
if (VRRootCapsule)
|
||||||
|
@ -932,8 +933,12 @@ void UVRCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iteration
|
||||||
const FVector OldVelocity = Velocity;
|
const FVector OldVelocity = Velocity;
|
||||||
Acceleration = FVector::VectorPlaneProject(Acceleration, -GetGravityDirection());
|
Acceleration = FVector::VectorPlaneProject(Acceleration, -GetGravityDirection());
|
||||||
|
|
||||||
|
|
||||||
|
static const auto CVarLedgeMovementApplyDirectMove = IConsoleManager::Get().FindConsoleVariable(TEXT("p.LedgeMovement.ApplyDirectMove"));
|
||||||
|
|
||||||
// Apply acceleration
|
// Apply acceleration
|
||||||
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
|
const bool bSkipForLedgeMove = bTriedLedgeMove && CVarLedgeMovementApplyDirectMove->GetBool();
|
||||||
|
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && !bSkipForLedgeMove)
|
||||||
{
|
{
|
||||||
CalcVelocity(timeTick, GroundFriction, false, GetMaxBrakingDeceleration());
|
CalcVelocity(timeTick, GroundFriction, false, GetMaxBrakingDeceleration());
|
||||||
devCodeVR(ensureMsgf(!Velocity.ContainsNaN(), TEXT("PhysWalking: Velocity contains NaN after CalcVelocity (%s)\n%s"), *GetPathNameSafe(this), *Velocity.ToString()));
|
devCodeVR(ensureMsgf(!Velocity.ContainsNaN(), TEXT("PhysWalking: Velocity contains NaN after CalcVelocity (%s)\n%s"), *GetPathNameSafe(this), *Velocity.ToString()));
|
||||||
|
@ -999,7 +1004,7 @@ void UVRCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iteration
|
||||||
const float DesiredDist = Delta.Size();
|
const float DesiredDist = Delta.Size();
|
||||||
if (DesiredDist > UE_KINDA_SMALL_NUMBER)
|
if (DesiredDist > UE_KINDA_SMALL_NUMBER)
|
||||||
{
|
{
|
||||||
const float ActualDist = (UpdatedComponent->GetComponentLocation() - OldLocation).Size2D();
|
const float ActualDist = ProjectToGravityFloor(UpdatedComponent->GetComponentLocation() - OldLocation).Size();
|
||||||
remainingTime += timeTick * (1.f - FMath::Min(1.f, ActualDist / DesiredDist));
|
remainingTime += timeTick * (1.f - FMath::Min(1.f, ActualDist / DesiredDist));
|
||||||
}
|
}
|
||||||
RestorePreAdditiveVRMotionVelocity();
|
RestorePreAdditiveVRMotionVelocity();
|
||||||
|
@ -1024,8 +1029,10 @@ void UVRCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iteration
|
||||||
if (bCheckLedges && !CurrentFloor.IsWalkableFloor())
|
if (bCheckLedges && !CurrentFloor.IsWalkableFloor())
|
||||||
{
|
{
|
||||||
// calculate possible alternate movement
|
// calculate possible alternate movement
|
||||||
const FVector GravDir = GetGravityDirection();
|
const FVector NewDelta = bTriedLedgeMove ? FVector::ZeroVector : GetLedgeMove(OldLocation, Delta, OldFloor);
|
||||||
const FVector NewDelta = bTriedLedgeMove ? FVector::ZeroVector : GetLedgeMove(OldCapsuleLocation, Delta, GravDir);
|
// REMOVED 5.5 and replaced with above
|
||||||
|
//const FVector GravDir = GetGravityDirection();
|
||||||
|
//const FVector NewDelta = bTriedLedgeMove ? FVector::ZeroVector : GetLedgeMove(OldCapsuleLocation, Delta, GravDir);
|
||||||
if (!NewDelta.IsZero())
|
if (!NewDelta.IsZero())
|
||||||
{
|
{
|
||||||
// first revert this move
|
// first revert this move
|
||||||
|
@ -1037,6 +1044,7 @@ void UVRCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iteration
|
||||||
// Try new movement direction
|
// Try new movement direction
|
||||||
Velocity = NewDelta / timeTick;
|
Velocity = NewDelta / timeTick;
|
||||||
remainingTime += timeTick;
|
remainingTime += timeTick;
|
||||||
|
Iterations--;
|
||||||
RestorePreAdditiveVRMotionVelocity();
|
RestorePreAdditiveVRMotionVelocity();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1084,7 +1092,7 @@ void UVRCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iteration
|
||||||
// The floor check failed because it started in penetration
|
// The floor check failed because it started in penetration
|
||||||
// We do not want to try to move downward because the downward sweep failed, rather we'd like to try to pop out of the floor.
|
// We do not want to try to move downward because the downward sweep failed, rather we'd like to try to pop out of the floor.
|
||||||
FHitResult Hit(CurrentFloor.HitResult);
|
FHitResult Hit(CurrentFloor.HitResult);
|
||||||
Hit.TraceEnd = Hit.TraceStart + RotateGravityToWorld(FVector(0.f, 0.f, MAX_FLOOR_DIST));
|
Hit.TraceEnd = Hit.TraceStart + MAX_FLOOR_DIST * -GetGravityDirection();
|
||||||
const FVector RequestedAdjustment = GetPenetrationAdjustment(Hit);
|
const FVector RequestedAdjustment = GetPenetrationAdjustment(Hit);
|
||||||
ResolvePenetration(RequestedAdjustment, Hit, UpdatedComponent->GetComponentQuat());
|
ResolvePenetration(RequestedAdjustment, Hit, UpdatedComponent->GetComponentQuat());
|
||||||
bForceNextFloorCheck = true;
|
bForceNextFloorCheck = true;
|
||||||
|
@ -1168,8 +1176,10 @@ void UVRCharacterMovementComponent::CapsuleTouched(UPrimitiveComponent* Overlapp
|
||||||
}
|
}
|
||||||
|
|
||||||
const FVector Loc = VRRootCapsule->OffsetComponentToWorld.GetLocation();//UpdatedComponent->GetComponentLocation();
|
const FVector Loc = VRRootCapsule->OffsetComponentToWorld.GetLocation();//UpdatedComponent->GetComponentLocation();
|
||||||
FVector ImpulseDir = FVector(OtherLoc.X - Loc.X, OtherLoc.Y - Loc.Y, 0.25f).GetSafeNormal();
|
|
||||||
ImpulseDir = (ImpulseDir + Velocity.GetSafeNormal2D()) * 0.5f;
|
FVector ImpulseDir = OtherLoc - Loc;
|
||||||
|
SetGravitySpaceZ(ImpulseDir, 0.25f);
|
||||||
|
ImpulseDir = (ImpulseDir.GetSafeNormal() + ProjectToGravityFloor(Velocity).GetSafeNormal()) * 0.5f;
|
||||||
ImpulseDir.Normalize();
|
ImpulseDir.Normalize();
|
||||||
|
|
||||||
FName BoneName = NAME_None;
|
FName BoneName = NAME_None;
|
||||||
|
@ -1186,7 +1196,7 @@ void UVRCharacterMovementComponent::CapsuleTouched(UPrimitiveComponent* Overlapp
|
||||||
TouchForceFactorModified *= BI ? BI->GetBodyMass() : 1.0f;
|
TouchForceFactorModified *= BI ? BI->GetBodyMass() : 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
float ImpulseStrength = FMath::Clamp(Velocity.Size2D() * TouchForceFactorModified,
|
float ImpulseStrength = FMath::Clamp<FVector::FReal>(ProjectToGravityFloor(Velocity).Size() * TouchForceFactorModified,
|
||||||
MinTouchForce > 0.0f ? MinTouchForce : -FLT_MAX,
|
MinTouchForce > 0.0f ? MinTouchForce : -FLT_MAX,
|
||||||
MaxTouchForce > 0.0f ? MaxTouchForce : FLT_MAX);
|
MaxTouchForce > 0.0f ? MaxTouchForce : FLT_MAX);
|
||||||
|
|
||||||
|
@ -1541,7 +1551,7 @@ void UVRCharacterMovementComponent::ApplyRepulsionForce(float DeltaSeconds)
|
||||||
// Trace to get the hit location on the capsule
|
// Trace to get the hit location on the capsule
|
||||||
FHitResult Hit;
|
FHitResult Hit;
|
||||||
bool bHasHit = UpdatedPrimitive->LineTraceComponent(Hit, BodyLocation,
|
bool bHasHit = UpdatedPrimitive->LineTraceComponent(Hit, BodyLocation,
|
||||||
FVector(MyLocation.X, MyLocation.Y, BodyLocation.Z),
|
ProjectToGravityFloor(MyLocation) + GetGravitySpaceComponentZ(BodyLocation),
|
||||||
QueryParams);
|
QueryParams);
|
||||||
|
|
||||||
FVector HitLoc = Hit.ImpactPoint;
|
FVector HitLoc = Hit.ImpactPoint;
|
||||||
|
@ -1554,12 +1564,12 @@ void UVRCharacterMovementComponent::ApplyRepulsionForce(float DeltaSeconds)
|
||||||
bIsPenetrating = true;
|
bIsPenetrating = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float DistanceNow = (HitLoc - BodyLocation).SizeSquared2D();
|
const float DistanceNow = ProjectToGravityFloor(HitLoc - BodyLocation).SizeSquared();
|
||||||
const float DistanceLater = (HitLoc - (BodyLocation + BodyVelocity * DeltaSeconds)).SizeSquared2D();
|
const float DistanceLater = ProjectToGravityFloor(HitLoc - (BodyLocation + BodyVelocity * DeltaSeconds)).SizeSquared();
|
||||||
|
|
||||||
if (bHasHit && DistanceNow < StopBodyDistance && !bIsPenetrating)
|
if (bHasHit && DistanceNow < StopBodyDistance && !bIsPenetrating)
|
||||||
{
|
{
|
||||||
OverlapBody->SetLinearVelocity(FVector(0.0f, 0.0f, 0.0f), false);
|
OverlapBody->SetLinearVelocity(FVector::ZeroVector, false);
|
||||||
}
|
}
|
||||||
else if (DistanceLater <= DistanceNow || bIsPenetrating)
|
else if (DistanceLater <= DistanceNow || bIsPenetrating)
|
||||||
{
|
{
|
||||||
|
@ -1567,11 +1577,12 @@ void UVRCharacterMovementComponent::ApplyRepulsionForce(float DeltaSeconds)
|
||||||
|
|
||||||
if (bHasHit)
|
if (bHasHit)
|
||||||
{
|
{
|
||||||
ForceCenter.Z = HitLoc.Z;
|
SetGravitySpaceZ(ForceCenter, GetGravitySpaceZ(HitLoc));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ForceCenter.Z = FMath::Clamp(BodyLocation.Z, MyLocation.Z - CapsuleHalfHeight, MyLocation.Z + CapsuleHalfHeight);
|
const FVector::FReal MyLocationZ = GetGravitySpaceZ(MyLocation);
|
||||||
|
SetGravitySpaceZ(ForceCenter, FMath::Clamp(GetGravitySpaceZ(BodyLocation), MyLocationZ - CapsuleHalfHeight, MyLocationZ + CapsuleHalfHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
OverlapBody->AddRadialForceToBody(ForceCenter, RepulsionForceRadius, RepulsionForce * Mass, ERadialImpulseFalloff::RIF_Constant);
|
OverlapBody->AddRadialForceToBody(ForceCenter, RepulsionForceRadius, RepulsionForce * Mass, ERadialImpulseFalloff::RIF_Constant);
|
||||||
|
@ -1650,7 +1661,7 @@ void UVRCharacterMovementComponent::MoveAlongFloor(const FVector& InVelocity, fl
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move along the current floor
|
// Move along the current floor
|
||||||
const FVector Delta = RotateGravityToWorld(RotateWorldToGravity(InVelocity) * FVector(1.0, 1.0, 0.0)) * DeltaSeconds;
|
const FVector Delta = ProjectToGravityFloor(InVelocity) * DeltaSeconds;
|
||||||
FHitResult Hit(1.f);
|
FHitResult Hit(1.f);
|
||||||
FVector RampVector = ComputeGroundMovementDelta(Delta, CurrentFloor.HitResult, CurrentFloor.bLineTrace);
|
FVector RampVector = ComputeGroundMovementDelta(Delta, CurrentFloor.HitResult, CurrentFloor.bLineTrace);
|
||||||
SafeMoveUpdatedComponent(RampVector, UpdatedComponent->GetComponentQuat(), true, Hit);
|
SafeMoveUpdatedComponent(RampVector, UpdatedComponent->GetComponentQuat(), true, Hit);
|
||||||
|
@ -1671,7 +1682,7 @@ void UVRCharacterMovementComponent::MoveAlongFloor(const FVector& InVelocity, fl
|
||||||
{
|
{
|
||||||
// We impacted something (most likely another ramp, but possibly a barrier).
|
// We impacted something (most likely another ramp, but possibly a barrier).
|
||||||
float PercentTimeApplied = Hit.Time;
|
float PercentTimeApplied = Hit.Time;
|
||||||
if ((Hit.Time > 0.f) && (Hit.Normal.Z > UE_KINDA_SMALL_NUMBER) && IsWalkable(Hit))
|
if ((Hit.Time > 0.f) && (GetGravitySpaceZ(Hit.Normal) > UE_KINDA_SMALL_NUMBER) && IsWalkable(Hit))
|
||||||
{
|
{
|
||||||
// Another walkable ramp.
|
// Another walkable ramp.
|
||||||
const float InitialPercentRemaining = 1.f - PercentTimeApplied;
|
const float InitialPercentRemaining = 1.f - PercentTimeApplied;
|
||||||
|
@ -1691,8 +1702,7 @@ void UVRCharacterMovementComponent::MoveAlongFloor(const FVector& InVelocity, fl
|
||||||
const FVector PreStepUpLocation = UpdatedComponent->GetComponentLocation();
|
const FVector PreStepUpLocation = UpdatedComponent->GetComponentLocation();
|
||||||
const FVector GravDir = GetGravityDirection();
|
const FVector GravDir = GetGravityDirection();
|
||||||
|
|
||||||
// I add in the HMD difference from last frame to the step up check to enforce it stepping up
|
if (!StepUp(GetGravityDirection(), Delta * (1.f - PercentTimeApplied), Hit, OutStepDownResult))
|
||||||
if (!StepUp(GravDir, (Delta * (1.f - PercentTimeApplied)) /*+ AdditionalVRInputVector.GetSafeNormal2D()*/, Hit, OutStepDownResult))
|
|
||||||
{
|
{
|
||||||
UE_LOG(LogVRCharacterMovement, Verbose, TEXT("- StepUp (ImpactNormal %s, Normal %s"), *Hit.ImpactNormal.ToString(), *Hit.Normal.ToString());
|
UE_LOG(LogVRCharacterMovement, Verbose, TEXT("- StepUp (ImpactNormal %s, Normal %s"), *Hit.ImpactNormal.ToString(), *Hit.Normal.ToString());
|
||||||
HandleImpact(Hit, LastMoveTimeSlice, RampVector);
|
HandleImpact(Hit, LastMoveTimeSlice, RampVector);
|
||||||
|
@ -1710,7 +1720,7 @@ void UVRCharacterMovementComponent::MoveAlongFloor(const FVector& InVelocity, fl
|
||||||
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && StepUpTimeSlice >= UE_KINDA_SMALL_NUMBER)
|
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && StepUpTimeSlice >= UE_KINDA_SMALL_NUMBER)
|
||||||
{
|
{
|
||||||
Velocity = (UpdatedComponent->GetComponentLocation() - PreStepUpLocation) / StepUpTimeSlice;
|
Velocity = (UpdatedComponent->GetComponentLocation() - PreStepUpLocation) / StepUpTimeSlice;
|
||||||
Velocity = FVector::VectorPlaneProject(Velocity, -GravDir);
|
Velocity = ProjectToGravityFloor(Velocity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1745,8 +1755,9 @@ bool UVRCharacterMovementComponent::StepUp(const FVector& GravDir, const FVector
|
||||||
CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnRadius, PawnHalfHeight);
|
CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnRadius, PawnHalfHeight);
|
||||||
|
|
||||||
// Don't bother stepping up if top of capsule is hitting something.
|
// Don't bother stepping up if top of capsule is hitting something.
|
||||||
const float InitialImpactZ = InHit.ImpactPoint.Z;
|
const float InitialImpactZ = InHit.ImpactPoint | -GravDir;
|
||||||
if (InitialImpactZ > OldLocation.Z + (PawnHalfHeight - PawnRadius))
|
const float OldLocationZ = OldLocation | -GravDir;
|
||||||
|
if (InitialImpactZ > OldLocationZ + (PawnHalfHeight - PawnRadius))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1762,7 +1773,7 @@ bool UVRCharacterMovementComponent::StepUp(const FVector& GravDir, const FVector
|
||||||
float StepTravelUpHeight = MaxStepHeight;
|
float StepTravelUpHeight = MaxStepHeight;
|
||||||
float StepTravelDownHeight = StepTravelUpHeight;
|
float StepTravelDownHeight = StepTravelUpHeight;
|
||||||
const float StepSideZ = -1.f * FVector::DotProduct(InHit.ImpactNormal, GravDir);//const float StepSideZ = -1.f * (InHit.ImpactNormal | GravDir);
|
const float StepSideZ = -1.f * FVector::DotProduct(InHit.ImpactNormal, GravDir);//const float StepSideZ = -1.f * (InHit.ImpactNormal | GravDir);
|
||||||
float PawnInitialFloorBaseZ = OldLocation.Z -PawnHalfHeight;
|
float PawnInitialFloorBaseZ = OldLocationZ - PawnHalfHeight;
|
||||||
float PawnFloorPointZ = PawnInitialFloorBaseZ;
|
float PawnFloorPointZ = PawnInitialFloorBaseZ;
|
||||||
|
|
||||||
if (IsMovingOnGround() && CurrentFloor.IsWalkableFloor())
|
if (IsMovingOnGround() && CurrentFloor.IsWalkableFloor())
|
||||||
|
@ -1776,7 +1787,7 @@ bool UVRCharacterMovementComponent::StepUp(const FVector& GravDir, const FVector
|
||||||
const bool bHitVerticalFace = !IsWithinEdgeTolerance(InHit.Location, InHit.ImpactPoint, PawnRadius);
|
const bool bHitVerticalFace = !IsWithinEdgeTolerance(InHit.Location, InHit.ImpactPoint, PawnRadius);
|
||||||
if (!CurrentFloor.bLineTrace && !bHitVerticalFace)
|
if (!CurrentFloor.bLineTrace && !bHitVerticalFace)
|
||||||
{
|
{
|
||||||
PawnFloorPointZ = CurrentFloor.HitResult.ImpactPoint.Z;
|
PawnFloorPointZ = CurrentFloor.HitResult.ImpactPoint | -GravDir;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1868,7 +1879,7 @@ bool UVRCharacterMovementComponent::StepUp(const FVector& GravDir, const FVector
|
||||||
if (Hit.IsValidBlockingHit())
|
if (Hit.IsValidBlockingHit())
|
||||||
{
|
{
|
||||||
// See if this step sequence would have allowed us to travel higher than our max step height allows.
|
// See if this step sequence would have allowed us to travel higher than our max step height allows.
|
||||||
const float DeltaZ = Hit.ImpactPoint.Z - PawnFloorPointZ;
|
const float DeltaZ = (Hit.ImpactPoint | -GravDir) - PawnFloorPointZ;
|
||||||
if (DeltaZ > MaxStepHeight)
|
if (DeltaZ > MaxStepHeight)
|
||||||
{
|
{
|
||||||
//UE_LOG(LogVRCharacterMovement, VeryVerbose, TEXT("- Reject StepUp (too high Height %.3f) up from floor base %f"), DeltaZ, PawnInitialFloorBaseZ);
|
//UE_LOG(LogVRCharacterMovement, VeryVerbose, TEXT("- Reject StepUp (too high Height %.3f) up from floor base %f"), DeltaZ, PawnInitialFloorBaseZ);
|
||||||
|
@ -1890,7 +1901,7 @@ bool UVRCharacterMovementComponent::StepUp(const FVector& GravDir, const FVector
|
||||||
|
|
||||||
// Also reject if we would end up being higher than our starting location by stepping down.
|
// Also reject if we would end up being higher than our starting location by stepping down.
|
||||||
// It's fine to step down onto an unwalkable normal below us, we will just slide off. Rejecting those moves would prevent us from being able to walk off the edge.
|
// It's fine to step down onto an unwalkable normal below us, we will just slide off. Rejecting those moves would prevent us from being able to walk off the edge.
|
||||||
if (Hit.Location.Z > OldLocation.Z)
|
if ((Hit.Location | -GravDir) > OldLocationZ)
|
||||||
{
|
{
|
||||||
//UE_LOG(LogVRCharacterMovement, VeryVerbose, TEXT("- Reject StepUp (unwalkable normal %s above old position)"), *Hit.ImpactNormal.ToString());
|
//UE_LOG(LogVRCharacterMovement, VeryVerbose, TEXT("- Reject StepUp (unwalkable normal %s above old position)"), *Hit.ImpactNormal.ToString());
|
||||||
ScopedStepUpMovement.RevertMove();
|
ScopedStepUpMovement.RevertMove();
|
||||||
|
@ -1921,7 +1932,7 @@ bool UVRCharacterMovementComponent::StepUp(const FVector& GravDir, const FVector
|
||||||
|
|
||||||
// Reject unwalkable normals if we end up higher than our initial height.
|
// Reject unwalkable normals if we end up higher than our initial height.
|
||||||
// It's fine to walk down onto an unwalkable surface, don't reject those moves.
|
// It's fine to walk down onto an unwalkable surface, don't reject those moves.
|
||||||
if (Hit.Location.Z > OldLocation.Z)
|
if ((Hit.Location | -GravDir) > OldLocationZ)
|
||||||
{
|
{
|
||||||
// We should reject the floor result if we are trying to step up an actual step where we are not able to perch (this is rare).
|
// We should reject the floor result if we are trying to step up an actual step where we are not able to perch (this is rare).
|
||||||
// In those cases we should instead abort the step up and try to slide along the stair.
|
// In those cases we should instead abort the step up and try to slide along the stair.
|
||||||
|
@ -1990,8 +2001,9 @@ bool UVRCharacterMovementComponent::VRClimbStepUp(const FVector& GravDir, const
|
||||||
CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnRadius, PawnHalfHeight);
|
CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnRadius, PawnHalfHeight);
|
||||||
|
|
||||||
// Don't bother stepping up if top of capsule is hitting something.
|
// Don't bother stepping up if top of capsule is hitting something.
|
||||||
const float InitialImpactZ = InHit.ImpactPoint.Z;
|
const float InitialImpactZ = InHit.ImpactPoint | -GravDir;
|
||||||
if (InitialImpactZ > OldLocation.Z + (PawnHalfHeight - PawnRadius))
|
const float OldLocationZ = OldLocation | -GravDir;
|
||||||
|
if (InitialImpactZ > OldLocationZ + (PawnHalfHeight - PawnRadius))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2013,7 +2025,7 @@ bool UVRCharacterMovementComponent::VRClimbStepUp(const FVector& GravDir, const
|
||||||
float StepTravelUpHeight = MaxStepHeight;
|
float StepTravelUpHeight = MaxStepHeight;
|
||||||
float StepTravelDownHeight = StepTravelUpHeight;
|
float StepTravelDownHeight = StepTravelUpHeight;
|
||||||
const float StepSideZ = -1.f * (InHit.ImpactNormal | GravDir);
|
const float StepSideZ = -1.f * (InHit.ImpactNormal | GravDir);
|
||||||
float PawnInitialFloorBaseZ = OldLocation.Z - PawnHalfHeight;
|
float PawnInitialFloorBaseZ = OldLocationZ - PawnHalfHeight;
|
||||||
float PawnFloorPointZ = PawnInitialFloorBaseZ;
|
float PawnFloorPointZ = PawnInitialFloorBaseZ;
|
||||||
|
|
||||||
// Scope our movement updates, and do not apply them until all intermediate moves are completed.
|
// Scope our movement updates, and do not apply them until all intermediate moves are completed.
|
||||||
|
@ -2109,7 +2121,7 @@ bool UVRCharacterMovementComponent::VRClimbStepUp(const FVector& GravDir, const
|
||||||
if (Hit.IsValidBlockingHit())
|
if (Hit.IsValidBlockingHit())
|
||||||
{
|
{
|
||||||
// See if this step sequence would have allowed us to travel higher than our max step height allows.
|
// See if this step sequence would have allowed us to travel higher than our max step height allows.
|
||||||
const float DeltaZ = Hit.ImpactPoint.Z - PawnFloorPointZ;
|
const float DeltaZ = (Hit.ImpactPoint | -GravDir) - PawnFloorPointZ;
|
||||||
if (DeltaZ > MaxStepHeight)
|
if (DeltaZ > MaxStepHeight)
|
||||||
{
|
{
|
||||||
UE_LOG(LogVRCharacterMovement, VeryVerbose, TEXT("- Reject StepUp (too high Height %.3f) up from floor base %f"), DeltaZ, PawnInitialFloorBaseZ);
|
UE_LOG(LogVRCharacterMovement, VeryVerbose, TEXT("- Reject StepUp (too high Height %.3f) up from floor base %f"), DeltaZ, PawnInitialFloorBaseZ);
|
||||||
|
@ -2131,7 +2143,7 @@ bool UVRCharacterMovementComponent::VRClimbStepUp(const FVector& GravDir, const
|
||||||
|
|
||||||
// Also reject if we would end up being higher than our starting location by stepping down.
|
// Also reject if we would end up being higher than our starting location by stepping down.
|
||||||
// It's fine to step down onto an unwalkable normal below us, we will just slide off. Rejecting those moves would prevent us from being able to walk off the edge.
|
// It's fine to step down onto an unwalkable normal below us, we will just slide off. Rejecting those moves would prevent us from being able to walk off the edge.
|
||||||
if (Hit.Location.Z > OldLocation.Z)
|
if ((Hit.Location | -GravDir) > OldLocationZ)
|
||||||
{
|
{
|
||||||
UE_LOG(LogVRCharacterMovement, VeryVerbose, TEXT("- Reject StepUp (unwalkable normal %s above old position)"), *Hit.ImpactNormal.ToString());
|
UE_LOG(LogVRCharacterMovement, VeryVerbose, TEXT("- Reject StepUp (unwalkable normal %s above old position)"), *Hit.ImpactNormal.ToString());
|
||||||
ScopedStepUpMovement.RevertMove();
|
ScopedStepUpMovement.RevertMove();
|
||||||
|
@ -2162,7 +2174,7 @@ bool UVRCharacterMovementComponent::VRClimbStepUp(const FVector& GravDir, const
|
||||||
|
|
||||||
// Reject unwalkable normals if we end up higher than our initial height.
|
// Reject unwalkable normals if we end up higher than our initial height.
|
||||||
// It's fine to walk down onto an unwalkable surface, don't reject those moves.
|
// It's fine to walk down onto an unwalkable surface, don't reject those moves.
|
||||||
if (Hit.Location.Z > OldLocation.Z)
|
if ((Hit.Location | -GravDir) > OldLocationZ)
|
||||||
{
|
{
|
||||||
// We should reject the floor result if we are trying to step up an actual step where we are not able to perch (this is rare).
|
// We should reject the floor result if we are trying to step up an actual step where we are not able to perch (this is rare).
|
||||||
// In those cases we should instead abort the step up and try to slide along the stair.
|
// In those cases we should instead abort the step up and try to slide along the stair.
|
||||||
|
@ -2195,6 +2207,12 @@ bool UVRCharacterMovementComponent::VRClimbStepUp(const FVector& GravDir, const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FVector UVRCharacterMovementComponent::GetActorFeetLocation() const
|
||||||
|
{
|
||||||
|
// Call into the VR version of it instead
|
||||||
|
return GetActorFeetLocationVR();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void UVRCharacterMovementComponent::UpdateBasedMovement(float DeltaSeconds)
|
void UVRCharacterMovementComponent::UpdateBasedMovement(float DeltaSeconds)
|
||||||
{
|
{
|
||||||
|
@ -2258,9 +2276,13 @@ void UVRCharacterMovementComponent::UpdateBasedMovement(float DeltaSeconds)
|
||||||
// Nothing changed. This means we probably are using another rotation mechanism (bOrientToMovement etc). We should still follow the base object.
|
// Nothing changed. This means we probably are using another rotation mechanism (bOrientToMovement etc). We should still follow the base object.
|
||||||
// @todo: This assumes only Yaw is used, currently a valid assumption. This is the only reason FaceRotation() is used above really, aside from being a virtual hook.
|
// @todo: This assumes only Yaw is used, currently a valid assumption. This is the only reason FaceRotation() is used above really, aside from being a virtual hook.
|
||||||
if (bOrientRotationToMovement || (bUseControllerDesiredRotation && CharacterOwner->Controller))
|
if (bOrientRotationToMovement || (bUseControllerDesiredRotation && CharacterOwner->Controller))
|
||||||
|
{
|
||||||
|
// Custom gravity automatically aligns the character to the gravity direction, so we shouldn't zero out pitch and roll.
|
||||||
|
if (!HasCustomGravity())
|
||||||
{
|
{
|
||||||
TargetRotator.Pitch = 0.f;
|
TargetRotator.Pitch = 0.f;
|
||||||
TargetRotator.Roll = 0.f;
|
TargetRotator.Roll = 0.f;
|
||||||
|
}
|
||||||
MoveUpdatedComponent(FVector::ZeroVector, TargetRotator, false);
|
MoveUpdatedComponent(FVector::ZeroVector, TargetRotator, false);
|
||||||
FinalQuat = UpdatedComponent->GetComponentQuat();
|
FinalQuat = UpdatedComponent->GetComponentQuat();
|
||||||
}
|
}
|
||||||
|
@ -2276,6 +2298,16 @@ void UVRCharacterMovementComponent::UpdateBasedMovement(float DeltaSeconds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FVector NewWorldPos;
|
||||||
|
if (HasCustomGravity())
|
||||||
|
{
|
||||||
|
const FVector RotationRadius = UpdatedComponent->GetComponentLocation() - NewBaseLocation;
|
||||||
|
const FVector RotationDelta = DeltaQuat.RotateVector(RotationRadius) - RotationRadius;
|
||||||
|
const FVector LinearDelta = NewBaseLocation - OldBaseLocation;
|
||||||
|
NewWorldPos = ConstrainLocationToPlane(UpdatedComponent->GetComponentLocation() + RotationDelta + LinearDelta);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// We need to offset the base of the character here, not its origin, so offset by half height
|
// We need to offset the base of the character here, not its origin, so offset by half height
|
||||||
float HalfHeight, Radius;
|
float HalfHeight, Radius;
|
||||||
CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(Radius, HalfHeight);
|
CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(Radius, HalfHeight);
|
||||||
|
@ -2288,7 +2320,9 @@ void UVRCharacterMovementComponent::UpdateBasedMovement(float DeltaSeconds)
|
||||||
FVector const BaseOffset(0.0f, 0.0f, HalfHeight);
|
FVector const BaseOffset(0.0f, 0.0f, HalfHeight);
|
||||||
|
|
||||||
FVector const LocalBasePos = OldLocalToWorld.InverseTransformPosition(UpdatedComponent->GetComponentLocation() - BaseOffset);
|
FVector const LocalBasePos = OldLocalToWorld.InverseTransformPosition(UpdatedComponent->GetComponentLocation() - BaseOffset);
|
||||||
FVector const NewWorldPos = ConstrainLocationToPlane(NewLocalToWorld.TransformPosition(LocalBasePos) + BaseOffset);
|
NewWorldPos = ConstrainLocationToPlane(NewLocalToWorld.TransformPosition(LocalBasePos) + BaseOffset);
|
||||||
|
}
|
||||||
|
|
||||||
DeltaPosition = ConstrainDirectionToPlane(NewWorldPos - UpdatedComponent->GetComponentLocation());
|
DeltaPosition = ConstrainDirectionToPlane(NewWorldPos - UpdatedComponent->GetComponentLocation());
|
||||||
|
|
||||||
// move attached actor
|
// move attached actor
|
||||||
|
@ -2377,16 +2411,13 @@ FVector UVRCharacterMovementComponent::GetImpartedMovementBaseVelocity() const
|
||||||
if (bImpartBaseAngularVelocity)
|
if (bImpartBaseAngularVelocity)
|
||||||
{
|
{
|
||||||
// Base position should be the bottom of the actor since I offset the capsule now
|
// Base position should be the bottom of the actor since I offset the capsule now
|
||||||
|
|
||||||
float HalfHeight = CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
|
float HalfHeight = CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
|
||||||
if (!BaseVRCharacterOwner || BaseVRCharacterOwner->bRetainRoomscale)
|
if (BaseVRCharacterOwner && BaseVRCharacterOwner->bRetainRoomscale)
|
||||||
{
|
{
|
||||||
HalfHeight = 0.0f;
|
HalfHeight = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FVector CharacterBasePosition = (UpdatedComponent->GetComponentLocation() - FVector(0.f, 0.f, HalfHeight));
|
const FVector CharacterBasePosition = (UpdatedComponent->GetComponentLocation() + HalfHeight * GetGravityDirection());
|
||||||
|
|
||||||
|
|
||||||
const FVector BaseTangentialVel = MovementBaseUtility::GetMovementBaseTangentialVelocity(MovementBase, CharacterOwner->GetBasedMovement().BoneName, CharacterBasePosition);
|
const FVector BaseTangentialVel = MovementBaseUtility::GetMovementBaseTangentialVelocity(MovementBase, CharacterOwner->GetBasedMovement().BoneName, CharacterBasePosition);
|
||||||
BaseVelocity += BaseTangentialVel;
|
BaseVelocity += BaseTangentialVel;
|
||||||
}
|
}
|
||||||
|
@ -2562,13 +2593,13 @@ float UVRCharacterMovementComponent::ImmersionDepth() const
|
||||||
|
|
||||||
if (VRRootCapsule)
|
if (VRRootCapsule)
|
||||||
{
|
{
|
||||||
TraceStart = VRRootCapsule->OffsetComponentToWorld.GetLocation() + FVector(0.f, 0.f, CollisionHalfHeight);
|
TraceStart = VRRootCapsule->OffsetComponentToWorld.GetLocation() + CollisionHalfHeight * -GetGravityDirection();
|
||||||
TraceEnd = VRRootCapsule->OffsetComponentToWorld.GetLocation() - FVector(0.f, 0.f, CollisionHalfHeight);
|
TraceEnd = VRRootCapsule->OffsetComponentToWorld.GetLocation() - CollisionHalfHeight * -GetGravityDirection();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TraceStart = UpdatedComponent->GetComponentLocation() + FVector(0.f, 0.f, CollisionHalfHeight);
|
TraceStart = UpdatedComponent->GetComponentLocation() + CollisionHalfHeight * -GetGravityDirection();
|
||||||
TraceEnd = UpdatedComponent->GetComponentLocation() -FVector(0.f, 0.f, CollisionHalfHeight);
|
TraceEnd = UpdatedComponent->GetComponentLocation() - CollisionHalfHeight * -GetGravityDirection();
|
||||||
}
|
}
|
||||||
|
|
||||||
FCollisionQueryParams NewTraceParams(CharacterMovementComponentStatics::ImmersionDepthName, true);
|
FCollisionQueryParams NewTraceParams(CharacterMovementComponentStatics::ImmersionDepthName, true);
|
||||||
|
@ -2669,18 +2700,19 @@ void UVRCharacterMovementComponent::PhysFlying(float deltaTime, int32 Iterations
|
||||||
|
|
||||||
if (Hit.Time < 1.f)
|
if (Hit.Time < 1.f)
|
||||||
{
|
{
|
||||||
const FVector GravDir = FVector(0.f, 0.f, -1.f);
|
|
||||||
const FVector VelDir = Velocity.GetSafeNormal();
|
const FVector VelDir = Velocity.GetSafeNormal();
|
||||||
const float UpDown = GravDir | VelDir;
|
const float UpDown = VelDir | GetGravityDirection();
|
||||||
|
|
||||||
|
|
||||||
bool bSteppedUp = false;
|
bool bSteppedUp = false;
|
||||||
if ((FMath::Abs(Hit.ImpactNormal.Z) < 0.2f) && (UpDown < 0.5f) && (UpDown > -0.2f) && CanStepUp(Hit))
|
if ((FMath::Abs(GetGravitySpaceZ(Hit.ImpactNormal)) < 0.2f) && (UpDown < 0.5f) && (UpDown > -0.2f) && CanStepUp(Hit))
|
||||||
{
|
{
|
||||||
float stepZ = UpdatedComponent->GetComponentLocation().Z;
|
const FVector::FReal StepZ = GetGravitySpaceZ(UpdatedComponent->GetComponentLocation());
|
||||||
bSteppedUp = StepUp(GravDir, (Adjusted + AdditionalVRInputVector) * (1.f - Hit.Time) /*+ AdditionalVRInputVector.GetSafeNormal2D()*/, Hit, nullptr);
|
bSteppedUp = StepUp(GetGravityDirection(), (Adjusted + AdditionalVRInputVector) * (1.f - Hit.Time), Hit);
|
||||||
if (bSteppedUp)
|
if (bSteppedUp)
|
||||||
{
|
{
|
||||||
OldLocation.Z = UpdatedComponent->GetComponentLocation().Z + (OldLocation.Z - stepZ);
|
const FVector::FReal LocationZ = GetGravitySpaceZ(UpdatedComponent->GetComponentLocation()) + (GetGravitySpaceZ(OldLocation) - StepZ);
|
||||||
|
SetGravitySpaceZ(OldLocation, LocationZ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2713,9 +2745,7 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FVector FallAcceleration = GetFallingLateralAcceleration(deltaTime);
|
const FVector FallAcceleration = ProjectToGravityFloor(GetFallingLateralAcceleration(deltaTime));
|
||||||
const FVector GravityRelativeFallAcceleration = RotateWorldToGravity(FallAcceleration);
|
|
||||||
FallAcceleration = RotateGravityToWorld(FVector(GravityRelativeFallAcceleration.X, GravityRelativeFallAcceleration.Y, 0));
|
|
||||||
const bool bHasLimitedAirControl = ShouldLimitAirControl(deltaTime, FallAcceleration);
|
const bool bHasLimitedAirControl = ShouldLimitAirControl(deltaTime, FallAcceleration);
|
||||||
|
|
||||||
// Rewind the players position by the new capsule location
|
// Rewind the players position by the new capsule location
|
||||||
|
@ -2751,7 +2781,7 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
||||||
TGuardValue<FVector> RestoreAcceleration(Acceleration, FallAcceleration);
|
TGuardValue<FVector> RestoreAcceleration(Acceleration, FallAcceleration);
|
||||||
if (HasCustomGravity())
|
if (HasCustomGravity())
|
||||||
{
|
{
|
||||||
Velocity = FVector::VectorPlaneProject(Velocity, RotateGravityToWorld(FVector::UpVector));
|
Velocity = ProjectToGravityFloor(Velocity);
|
||||||
const FVector GravityRelativeOffset = OldVelocity - Velocity;
|
const FVector GravityRelativeOffset = OldVelocity - Velocity;
|
||||||
CalcVelocity(timeTick, FallingLateralFriction, false, MaxDecel);
|
CalcVelocity(timeTick, FallingLateralFriction, false, MaxDecel);
|
||||||
Velocity += GravityRelativeOffset;
|
Velocity += GravityRelativeOffset;
|
||||||
|
@ -2797,15 +2827,15 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
||||||
DecayFormerBaseVelocity(timeTick);
|
DecayFormerBaseVelocity(timeTick);
|
||||||
|
|
||||||
// See if we need to sub-step to exactly reach the apex. This is important for avoiding "cutting off the top" of the trajectory as framerate varies.
|
// See if we need to sub-step to exactly reach the apex. This is important for avoiding "cutting off the top" of the trajectory as framerate varies.
|
||||||
const FVector GravityRelativeOldVelocityWithRootMotion = RotateWorldToGravity(OldVelocityWithRootMotion);
|
const FVector::FReal GravityRelativeOldVelocityWithRootMotionZ = GetGravitySpaceZ(OldVelocityWithRootMotion);
|
||||||
static const auto CVarForceJumpPeakSubstep = IConsoleManager::Get().FindConsoleVariable(TEXT("p.ForceJumpPeakSubstep"));
|
static const auto CVarForceJumpPeakSubstep = IConsoleManager::Get().FindConsoleVariable(TEXT("p.ForceJumpPeakSubstep"));
|
||||||
if (CVarForceJumpPeakSubstep->GetInt() != 0 && GravityRelativeOldVelocityWithRootMotion.Z > 0.f && RotateWorldToGravity(Velocity).Z <= 0.f && NumJumpApexAttempts < MaxJumpApexAttemptsPerSimulation)
|
if (CVarForceJumpPeakSubstep->GetInt() && GravityRelativeOldVelocityWithRootMotionZ > 0.f && GetGravitySpaceZ(Velocity) <= 0.f && NumJumpApexAttempts < MaxJumpApexAttemptsPerSimulation)
|
||||||
{
|
{
|
||||||
const FVector DerivedAccel = (Velocity - OldVelocityWithRootMotion) / timeTick;
|
const FVector DerivedAccel = (Velocity - OldVelocityWithRootMotion) / timeTick;
|
||||||
const FVector GravityRelativeDerivedAccel = RotateWorldToGravity(DerivedAccel);
|
const FVector::FReal GravityRelativeDerivedAccelZ = GetGravitySpaceZ(DerivedAccel);
|
||||||
if (!FMath::IsNearlyZero(GravityRelativeDerivedAccel.Z))
|
if (!FMath::IsNearlyZero(GravityRelativeDerivedAccelZ))
|
||||||
{
|
{
|
||||||
const float TimeToApex = -GravityRelativeOldVelocityWithRootMotion.Z / GravityRelativeDerivedAccel.Z;
|
const float TimeToApex = -GravityRelativeOldVelocityWithRootMotionZ / GravityRelativeDerivedAccelZ;
|
||||||
|
|
||||||
// The time-to-apex calculation should be precise, and we want to avoid adding a substep when we are basically already at the apex from the previous iteration's work.
|
// The time-to-apex calculation should be precise, and we want to avoid adding a substep when we are basically already at the apex from the previous iteration's work.
|
||||||
const float ApexTimeMinimum = 0.0001f;
|
const float ApexTimeMinimum = 0.0001f;
|
||||||
|
@ -2814,8 +2844,7 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
||||||
const FVector ApexVelocity = OldVelocityWithRootMotion + (DerivedAccel * TimeToApex);
|
const FVector ApexVelocity = OldVelocityWithRootMotion + (DerivedAccel * TimeToApex);
|
||||||
if (HasCustomGravity())
|
if (HasCustomGravity())
|
||||||
{
|
{
|
||||||
const FVector GravityRelativeApexVelocity = RotateWorldToGravity(ApexVelocity);
|
Velocity = ProjectToGravityFloor(ApexVelocity); // Should be nearly zero anyway, but this makes apex notifications consistent.
|
||||||
Velocity = RotateGravityToWorld(FVector(GravityRelativeApexVelocity.X, GravityRelativeApexVelocity.Y, 0)); // Should be nearly zero anyway, but this makes apex notifications consistent.
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2847,7 +2876,7 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
||||||
ApplyRootMotionToVelocity(timeTick);
|
ApplyRootMotionToVelocity(timeTick);
|
||||||
//ApplyVRMotionToVelocity(deltaTime);
|
//ApplyVRMotionToVelocity(deltaTime);
|
||||||
|
|
||||||
if (bNotifyApex && (RotateWorldToGravity(Velocity).Z < 0.f))
|
if (bNotifyApex && (GetGravitySpaceZ(Velocity) < 0.f))
|
||||||
{
|
{
|
||||||
// Just passed jump apex since now going down
|
// Just passed jump apex since now going down
|
||||||
bNotifyApex = false;
|
bNotifyApex = false;
|
||||||
|
@ -2912,7 +2941,9 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
||||||
|
|
||||||
FFindFloorResult FloorResult;
|
FFindFloorResult FloorResult;
|
||||||
FindFloor(PawnLocation, FloorResult, false, NULL);
|
FindFloor(PawnLocation, FloorResult, false, NULL);
|
||||||
if (FloorResult.IsWalkableFloor() && IsValidLandingSpot(PawnLocation, FloorResult.HitResult))
|
|
||||||
|
// Note that we only care about capsule sweep floor results, since the line trace may detect a lower walkable surface that our falling capsule wouldn't actually reach yet.
|
||||||
|
if (!FloorResult.bLineTrace && FloorResult.IsWalkableFloor() && IsValidLandingSpot(PawnLocation, FloorResult.HitResult))
|
||||||
{
|
{
|
||||||
//RestorePreAdditiveVRMotionVelocity();
|
//RestorePreAdditiveVRMotionVelocity();
|
||||||
remainingTime += subTimeTickRemaining;
|
remainingTime += subTimeTickRemaining;
|
||||||
|
@ -2950,7 +2981,7 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
||||||
TGuardValue<FVector> RestoreVelocity(Velocity, OldVelocity);
|
TGuardValue<FVector> RestoreVelocity(Velocity, OldVelocity);
|
||||||
if (HasCustomGravity())
|
if (HasCustomGravity())
|
||||||
{
|
{
|
||||||
Velocity = FVector::VectorPlaneProject(Velocity, RotateGravityToWorld(FVector::UpVector));
|
Velocity = ProjectToGravityFloor(Velocity);
|
||||||
const FVector GravityRelativeOffset = OldVelocity - Velocity;
|
const FVector GravityRelativeOffset = OldVelocity - Velocity;
|
||||||
CalcVelocity(timeTick, FallingLateralFriction, false, MaxDecel);
|
CalcVelocity(timeTick, FallingLateralFriction, false, MaxDecel);
|
||||||
VelocityNoAirControl = Velocity + GravityRelativeOffset;
|
VelocityNoAirControl = Velocity + GravityRelativeOffset;
|
||||||
|
@ -2981,12 +3012,12 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
||||||
{
|
{
|
||||||
const FVector ContactVelocity = MovementBaseUtility::GetMovementBaseVelocity(HitComponent, NAME_None) + MovementBaseUtility::GetMovementBaseTangentialVelocity(HitComponent, NAME_None, Hit.ImpactPoint);
|
const FVector ContactVelocity = MovementBaseUtility::GetMovementBaseVelocity(HitComponent, NAME_None) + MovementBaseUtility::GetMovementBaseTangentialVelocity(HitComponent, NAME_None, Hit.ImpactPoint);
|
||||||
const FVector NewVelocity = Velocity - Hit.ImpactNormal * FVector::DotProduct(Velocity - ContactVelocity, Hit.ImpactNormal);
|
const FVector NewVelocity = Velocity - Hit.ImpactNormal * FVector::DotProduct(Velocity - ContactVelocity, Hit.ImpactNormal);
|
||||||
Velocity = HasAnimRootMotion() || CurrentRootMotion.HasOverrideVelocityWithIgnoreZAccumulate() ? FVector(Velocity.X, Velocity.Y, NewVelocity.Z) : NewVelocity;
|
Velocity = HasAnimRootMotion() || CurrentRootMotion.HasOverrideVelocityWithIgnoreZAccumulate() ? ProjectToGravityFloor(Velocity) + GetGravitySpaceComponentZ(NewVelocity) : NewVelocity;
|
||||||
}
|
}
|
||||||
else if (subTimeTickRemaining > UE_KINDA_SMALL_NUMBER && !bJustTeleported)
|
else if (subTimeTickRemaining > UE_KINDA_SMALL_NUMBER && !bJustTeleported)
|
||||||
{
|
{
|
||||||
const FVector NewVelocity = (Delta / subTimeTickRemaining);
|
const FVector NewVelocity = (Delta / subTimeTickRemaining);
|
||||||
Velocity = HasAnimRootMotion() || CurrentRootMotion.HasOverrideVelocityWithIgnoreZAccumulate() ? FVector(Velocity.X, Velocity.Y, NewVelocity.Z) : NewVelocity;
|
Velocity = HasAnimRootMotion() || CurrentRootMotion.HasOverrideVelocityWithIgnoreZAccumulate() ? ProjectToGravityFloor(Velocity) + GetGravitySpaceComponentZ(NewVelocity) : NewVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subTimeTickRemaining > UE_KINDA_SMALL_NUMBER && (Delta | Adjusted) > 0.f)
|
if (subTimeTickRemaining > UE_KINDA_SMALL_NUMBER && (Delta | Adjusted) > 0.f)
|
||||||
|
@ -3019,7 +3050,7 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
||||||
}
|
}
|
||||||
|
|
||||||
// Act as if there was no air control on the last move when computing new deflection.
|
// Act as if there was no air control on the last move when computing new deflection.
|
||||||
if (bHasLimitedAirControl && RotateWorldToGravity(Hit.Normal).Z > CharacterMovementConstants::VERTICAL_SLOPE_NORMAL_ZVR)
|
if (bHasLimitedAirControl && GetGravitySpaceZ(Hit.Normal) > CharacterMovementConstants::VERTICAL_SLOPE_NORMAL_ZVR)
|
||||||
{
|
{
|
||||||
const FVector LastMoveNoAirControl = VelocityNoAirControl * LastMoveTimeSlice;
|
const FVector LastMoveNoAirControl = VelocityNoAirControl * LastMoveTimeSlice;
|
||||||
Delta = ComputeSlideVector(LastMoveNoAirControl, 1.f, OldHitNormal, Hit);
|
Delta = ComputeSlideVector(LastMoveNoAirControl, 1.f, OldHitNormal, Hit);
|
||||||
|
@ -3045,20 +3076,28 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
||||||
if (subTimeTickRemaining > UE_KINDA_SMALL_NUMBER && !bJustTeleported)
|
if (subTimeTickRemaining > UE_KINDA_SMALL_NUMBER && !bJustTeleported)
|
||||||
{
|
{
|
||||||
const FVector NewVelocity = (Delta / subTimeTickRemaining);
|
const FVector NewVelocity = (Delta / subTimeTickRemaining);
|
||||||
Velocity = HasAnimRootMotion() || CurrentRootMotion.HasOverrideVelocityWithIgnoreZAccumulate() ? FVector(Velocity.X, Velocity.Y, NewVelocity.Z) : NewVelocity;
|
Velocity = HasAnimRootMotion() || CurrentRootMotion.HasOverrideVelocityWithIgnoreZAccumulate() ? ProjectToGravityFloor(Velocity) + GetGravitySpaceComponentZ(NewVelocity) : NewVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bDitch=true means that pawn is straddling two slopes, neither of which he can stand on
|
// bDitch=true means that pawn is straddling two slopes, neither of which he can stand on
|
||||||
bool bDitch = ((RotateWorldToGravity(OldHitImpactNormal).Z > 0.f) && (RotateWorldToGravity(Hit.ImpactNormal).Z > 0.f) && (FMath::Abs(Delta.Z) <= UE_KINDA_SMALL_NUMBER) && ((Hit.ImpactNormal | OldHitImpactNormal) < 0.f));
|
bool bDitch = ((GetGravitySpaceZ(OldHitImpactNormal) > 0.f) && (GetGravitySpaceZ(Hit.ImpactNormal) > 0.f) && (FMath::Abs(GetGravitySpaceZ(Delta)) <= UE_KINDA_SMALL_NUMBER) && ((Hit.ImpactNormal | OldHitImpactNormal) < 0.f));
|
||||||
SafeMoveUpdatedComponent(Delta, PawnRotation, true, Hit);
|
SafeMoveUpdatedComponent(Delta, PawnRotation, true, Hit);
|
||||||
if (Hit.Time == 0.f)
|
if (Hit.Time == 0.f)
|
||||||
{
|
{
|
||||||
// if we are stuck then try to side step
|
// if we are stuck then try to side step
|
||||||
FVector SideDelta = (OldHitNormal + Hit.ImpactNormal).GetSafeNormal2D();
|
FVector SideDelta = ProjectToGravityFloor(OldHitNormal + Hit.ImpactNormal).GetSafeNormal();
|
||||||
if (SideDelta.IsNearlyZero())
|
if (SideDelta.IsNearlyZero())
|
||||||
|
{
|
||||||
|
if (HasCustomGravity())
|
||||||
|
{
|
||||||
|
const FVector GravityRelativeHitNormal = RotateWorldToGravity(OldHitNormal);
|
||||||
|
SideDelta = RotateGravityToWorld(FVector(GravityRelativeHitNormal.Y, -GravityRelativeHitNormal.X, 0.f)).GetSafeNormal();
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
SideDelta = FVector(OldHitNormal.Y, -OldHitNormal.X, 0).GetSafeNormal();
|
SideDelta = FVector(OldHitNormal.Y, -OldHitNormal.X, 0).GetSafeNormal();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
SafeMoveUpdatedComponent(SideDelta, PawnRotation, true, Hit);
|
SafeMoveUpdatedComponent(SideDelta, PawnRotation, true, Hit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3069,13 +3108,13 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
||||||
ProcessLanded(Hit, remainingTime, Iterations);
|
ProcessLanded(Hit, remainingTime, Iterations);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (GetPerchRadiusThreshold() > 0.f && Hit.Time == 1.f && RotateWorldToGravity(OldHitImpactNormal).Z >= GetWalkableFloorZ())
|
else if (GetPerchRadiusThreshold() > 0.f && Hit.Time == 1.f && GetGravitySpaceZ(OldHitImpactNormal) >= GetWalkableFloorZ())
|
||||||
{
|
{
|
||||||
// We might be in a virtual 'ditch' within our perch radius. This is rare.
|
// We might be in a virtual 'ditch' within our perch radius. This is rare.
|
||||||
const FVector PawnLocation = UpdatedComponent->GetComponentLocation();
|
const FVector PawnLocation = UpdatedComponent->GetComponentLocation();
|
||||||
const float ZMovedDist = FMath::Abs(RotateWorldToGravity(PawnLocation - OldLocation).Z);
|
const float ZMovedDist = FMath::Abs(GetGravitySpaceZ(PawnLocation - OldLocation));
|
||||||
const float MovedDist2DSq = FVector::VectorPlaneProject(PawnLocation - OldLocation, RotateGravityToWorld(FVector::UpVector)).Size2D();
|
const float MovedDist2D = ProjectToGravityFloor(PawnLocation - OldLocation).Size();
|
||||||
if (ZMovedDist <= 0.2f * timeTick && MovedDist2DSq <= 4.f * timeTick)
|
if (ZMovedDist <= 0.2f * timeTick && MovedDist2D <= 4.f * timeTick)
|
||||||
{
|
{
|
||||||
FVector GravityRelativeVelocity = RotateWorldToGravity(Velocity);
|
FVector GravityRelativeVelocity = RotateWorldToGravity(Velocity);
|
||||||
GravityRelativeVelocity.X += 0.25f * GetMaxSpeed() * (RandomStream.FRand() - 0.5f);
|
GravityRelativeVelocity.X += 0.25f * GetMaxSpeed() * (RandomStream.FRand() - 0.5f);
|
||||||
|
@ -3135,12 +3174,10 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FVector GravityRelativeVelocity = RotateWorldToGravity(Velocity);
|
const FVector GravityProjectedVelocity = ProjectToGravityFloor(Velocity);
|
||||||
if (GravityRelativeVelocity.SizeSquared2D() <= UE_KINDA_SMALL_NUMBER * 10.f)
|
if (GravityProjectedVelocity.SizeSquared() <= UE_KINDA_SMALL_NUMBER * 10.f)
|
||||||
{
|
{
|
||||||
GravityRelativeVelocity.X = 0.f;
|
Velocity = GetGravitySpaceComponentZ(Velocity);
|
||||||
GravityRelativeVelocity.Y = 0.f;
|
|
||||||
Velocity = RotateGravityToWorld(GravityRelativeVelocity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RestorePreAdditiveVRMotionVelocity();
|
RestorePreAdditiveVRMotionVelocity();
|
||||||
|
@ -3179,7 +3216,7 @@ void UVRCharacterMovementComponent::PhysNavWalking(float deltaTime, int32 Iterat
|
||||||
devCodeVR(ensureMsgf(!Velocity.ContainsNaN(), TEXT("PhysNavWalking: Velocity contains NaN before CalcVelocity (%s)\n%s"), *GetPathNameSafe(this), *Velocity.ToString()));
|
devCodeVR(ensureMsgf(!Velocity.ContainsNaN(), TEXT("PhysNavWalking: Velocity contains NaN before CalcVelocity (%s)\n%s"), *GetPathNameSafe(this), *Velocity.ToString()));
|
||||||
|
|
||||||
//bound acceleration
|
//bound acceleration
|
||||||
Acceleration.Z = 0.f;
|
Acceleration = ProjectToGravityFloor(Acceleration);
|
||||||
//if (!HasRootMotion())
|
//if (!HasRootMotion())
|
||||||
//{
|
//{
|
||||||
CalcVelocity(deltaTime, GroundFriction, false, BrakingDecelerationWalking);
|
CalcVelocity(deltaTime, GroundFriction, false, BrakingDecelerationWalking);
|
||||||
|
@ -3198,8 +3235,7 @@ void UVRCharacterMovementComponent::PhysNavWalking(float deltaTime, int32 Iterat
|
||||||
|
|
||||||
Iterations++;
|
Iterations++;
|
||||||
|
|
||||||
FVector DesiredMove = Velocity;
|
const FVector DesiredMove = ProjectToGravityFloor(Velocity);
|
||||||
DesiredMove.Z = 0.f;
|
|
||||||
|
|
||||||
//const FVector OldPlayerLocation = GetActorFeetLocation();
|
//const FVector OldPlayerLocation = GetActorFeetLocation();
|
||||||
const FVector OldLocation = GetActorFeetLocationVR();
|
const FVector OldLocation = GetActorFeetLocationVR();
|
||||||
|
@ -3214,11 +3250,11 @@ void UVRCharacterMovementComponent::PhysNavWalking(float deltaTime, int32 Iterat
|
||||||
{
|
{
|
||||||
if (bProjectNavMeshWalking)
|
if (bProjectNavMeshWalking)
|
||||||
{
|
{
|
||||||
const float DistSq2D = (OldLocation - CachedNavLocation.Location).SizeSquared2D();
|
const float DistSq2D = ProjectToGravityFloor(OldLocation - CachedNavLocation.Location).SizeSquared();
|
||||||
const float DistZ = FMath::Abs(OldLocation.Z - CachedNavLocation.Location.Z);
|
const float DistZ = FMath::Abs(GetGravitySpaceZ(OldLocation - CachedNavLocation.Location));
|
||||||
|
|
||||||
const float TotalCapsuleHeight = CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight() * 2.0f;
|
const float TotalCapsuleHeight = CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight() * 2.0f;
|
||||||
const float ProjectionScale = (OldLocation.Z > CachedNavLocation.Location.Z) ? NavMeshProjectionHeightScaleUp : NavMeshProjectionHeightScaleDown;
|
const float ProjectionScale = (GetGravitySpaceZ(OldLocation) > GetGravitySpaceZ(CachedNavLocation.Location)) ? NavMeshProjectionHeightScaleUp : NavMeshProjectionHeightScaleDown;
|
||||||
const float DistZThr = TotalCapsuleHeight * FMath::Max(0.f, ProjectionScale);
|
const float DistZThr = TotalCapsuleHeight * FMath::Max(0.f, ProjectionScale);
|
||||||
|
|
||||||
bSameNavLocation = (DistSq2D <= UE_KINDA_SMALL_NUMBER) && (DistZ < DistZThr);
|
bSameNavLocation = (DistSq2D <= UE_KINDA_SMALL_NUMBER) && (DistZ < DistZThr);
|
||||||
|
@ -3255,7 +3291,7 @@ void UVRCharacterMovementComponent::PhysNavWalking(float deltaTime, int32 Iterat
|
||||||
// we'll follow that geometry's plane out of range of valid navigation.
|
// we'll follow that geometry's plane out of range of valid navigation.
|
||||||
if (bSameNavLocation && bProjectNavMeshWalking)
|
if (bSameNavLocation && bProjectNavMeshWalking)
|
||||||
{
|
{
|
||||||
AdjustedDest.Z = CachedNavLocation.Location.Z;
|
SetGravitySpaceZ(AdjustedDest, GetGravitySpaceZ(CachedNavLocation.Location));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the point on the NavMesh
|
// Find the point on the NavMesh
|
||||||
|
@ -3272,7 +3308,7 @@ void UVRCharacterMovementComponent::PhysNavWalking(float deltaTime, int32 Iterat
|
||||||
|
|
||||||
if (DestNavLocation.NodeRef != INVALID_NAVNODEREF)
|
if (DestNavLocation.NodeRef != INVALID_NAVNODEREF)
|
||||||
{
|
{
|
||||||
FVector NewLocation(AdjustedDest.X, AdjustedDest.Y, DestNavLocation.Location.Z);
|
FVector NewLocation = ProjectToGravityFloor(AdjustedDest) + GetGravitySpaceComponentZ(DestNavLocation.Location);
|
||||||
if (bProjectNavMeshWalking)
|
if (bProjectNavMeshWalking)
|
||||||
{
|
{
|
||||||
SCOPE_CYCLE_COUNTER(STAT_CharNavProjectLocation);
|
SCOPE_CYCLE_COUNTER(STAT_CharNavProjectLocation);
|
||||||
|
@ -3330,18 +3366,18 @@ void UVRCharacterMovementComponent::PhysSwimming(float deltaTime, int32 Iteratio
|
||||||
float NetFluidFriction = 0.f;
|
float NetFluidFriction = 0.f;
|
||||||
float Depth = ImmersionDepth();
|
float Depth = ImmersionDepth();
|
||||||
float NetBuoyancy = Buoyancy * Depth;
|
float NetBuoyancy = Buoyancy * Depth;
|
||||||
float OriginalAccelZ = Acceleration.Z;
|
float OriginalAccelZ = GetGravitySpaceZ(Acceleration);
|
||||||
bool bLimitedUpAccel = false;
|
bool bLimitedUpAccel = false;
|
||||||
|
|
||||||
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && (Velocity.Z > 0.33f * MaxSwimSpeed) && (NetBuoyancy != 0.f))
|
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && (GetGravitySpaceZ(Velocity) > 0.33f * MaxSwimSpeed) && (NetBuoyancy != 0.f))
|
||||||
{
|
{
|
||||||
//damp positive Z out of water
|
//damp positive Z out of water
|
||||||
Velocity.Z = FMath::Max<FVector::FReal>(0.33f * MaxSwimSpeed, Velocity.Z * Depth * Depth);
|
SetGravitySpaceZ(Velocity, FMath::Max<FVector::FReal>(0.33f * MaxSwimSpeed, GetGravitySpaceZ(Velocity) * Depth * Depth));
|
||||||
}
|
}
|
||||||
else if (Depth < 0.65f)
|
else if (Depth < 0.65f)
|
||||||
{
|
{
|
||||||
bLimitedUpAccel = (Acceleration.Z > 0.f);
|
bLimitedUpAccel = (OriginalAccelZ > 0.f);
|
||||||
Acceleration.Z = FMath::Min<FVector::FReal>(0.1f, Acceleration.Z);
|
SetGravitySpaceZ(Acceleration, FMath::Min<FVector::FReal>(0.1f, OriginalAccelZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterations++;
|
Iterations++;
|
||||||
|
@ -3351,7 +3387,7 @@ void UVRCharacterMovementComponent::PhysSwimming(float deltaTime, int32 Iteratio
|
||||||
{
|
{
|
||||||
const float Friction = 0.5f * GetPhysicsVolume()->FluidFriction * Depth;
|
const float Friction = 0.5f * GetPhysicsVolume()->FluidFriction * Depth;
|
||||||
CalcVelocity(deltaTime, Friction, true, GetMaxBrakingDeceleration());
|
CalcVelocity(deltaTime, Friction, true, GetMaxBrakingDeceleration());
|
||||||
Velocity.Z += GetGravityZ() * deltaTime * (1.f - NetBuoyancy);
|
Velocity += (GetGravityZ() * deltaTime * (1.f - NetBuoyancy)) * -GetGravityDirection();
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplyRootMotionToVelocity(deltaTime);
|
ApplyRootMotionToVelocity(deltaTime);
|
||||||
|
@ -3359,7 +3395,7 @@ void UVRCharacterMovementComponent::PhysSwimming(float deltaTime, int32 Iteratio
|
||||||
|
|
||||||
FVector Adjusted = Velocity * deltaTime;
|
FVector Adjusted = Velocity * deltaTime;
|
||||||
FHitResult Hit(1.f);
|
FHitResult Hit(1.f);
|
||||||
float remainingTime = deltaTime * SwimVR(Adjusted/* + AdditionalVRInputVector*/, Hit);
|
const float remainingTime = deltaTime * Swim(Adjusted, Hit);
|
||||||
|
|
||||||
//may have left water - if so, script might have set new physics mode
|
//may have left water - if so, script might have set new physics mode
|
||||||
if (!IsSwimming())
|
if (!IsSwimming())
|
||||||
|
@ -3372,10 +3408,10 @@ void UVRCharacterMovementComponent::PhysSwimming(float deltaTime, int32 Iteratio
|
||||||
if (Hit.Time < 1.f && CharacterOwner)
|
if (Hit.Time < 1.f && CharacterOwner)
|
||||||
{
|
{
|
||||||
HandleSwimmingWallHit(Hit, deltaTime);
|
HandleSwimmingWallHit(Hit, deltaTime);
|
||||||
if (bLimitedUpAccel && (Velocity.Z >= 0.f))
|
if (bLimitedUpAccel && (GetGravitySpaceZ(Velocity) >= 0.f))
|
||||||
{
|
{
|
||||||
// allow upward velocity at surface if against obstacle
|
// allow upward velocity at surface if against obstacle
|
||||||
Velocity.Z += OriginalAccelZ * deltaTime;
|
Velocity += OriginalAccelZ * deltaTime * -GetGravityDirection();
|
||||||
Adjusted = Velocity * (1.f - Hit.Time)*deltaTime;
|
Adjusted = Velocity * (1.f - Hit.Time)*deltaTime;
|
||||||
SwimVR(Adjusted, Hit);
|
SwimVR(Adjusted, Hit);
|
||||||
if (!IsSwimming())
|
if (!IsSwimming())
|
||||||
|
@ -3386,17 +3422,16 @@ void UVRCharacterMovementComponent::PhysSwimming(float deltaTime, int32 Iteratio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const FVector GravDir = FVector(0.f, 0.f, -1.f);
|
|
||||||
const FVector VelDir = Velocity.GetSafeNormal();
|
const FVector VelDir = Velocity.GetSafeNormal();
|
||||||
const float UpDown = GravDir | VelDir;
|
const float UpDown = VelDir | GetGravityDirection();
|
||||||
|
|
||||||
bool bSteppedUp = false;
|
bool bSteppedUp = false;
|
||||||
if ((FMath::Abs(Hit.ImpactNormal.Z) < 0.2f) && (UpDown < 0.5f) && (UpDown > -0.2f) && CanStepUp(Hit))
|
if ((FMath::Abs(GetGravitySpaceZ(Hit.ImpactNormal)) < 0.2f) && (UpDown < 0.5f) && (UpDown > -0.2f) && CanStepUp(Hit))
|
||||||
{
|
{
|
||||||
float stepZ = UpdatedComponent->GetComponentLocation().Z;
|
const float StepZ = GetGravitySpaceZ(UpdatedComponent->GetComponentLocation());
|
||||||
const FVector RealVelocity = Velocity;
|
const FVector RealVelocity = Velocity;
|
||||||
Velocity.Z = 1.f; // HACK: since will be moving up, in case pawn leaves the water
|
SetGravitySpaceZ(Velocity, 1.f); // HACK: since will be moving up, in case pawn leaves the water
|
||||||
bSteppedUp = StepUp(GravDir, (Adjusted/* + AdditionalVRInputVector*/) * (1.f - Hit.Time), Hit);
|
bSteppedUp = StepUp(GetGravityDirection(), Adjusted * (1.f - Hit.Time), Hit);
|
||||||
if (bSteppedUp)
|
if (bSteppedUp)
|
||||||
{
|
{
|
||||||
//may have left water - if so, script might have set new physics mode
|
//may have left water - if so, script might have set new physics mode
|
||||||
|
@ -3406,7 +3441,7 @@ void UVRCharacterMovementComponent::PhysSwimming(float deltaTime, int32 Iteratio
|
||||||
StartNewPhysics(remainingTime, Iterations);
|
StartNewPhysics(remainingTime, Iterations);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
OldLocation.Z = UpdatedComponent->GetComponentLocation().Z + (OldLocation.Z - stepZ);
|
SetGravitySpaceZ(OldLocation, GetGravitySpaceZ(UpdatedComponent->GetComponentLocation()) + (GetGravitySpaceZ(OldLocation) - StepZ));
|
||||||
}
|
}
|
||||||
Velocity = RealVelocity;
|
Velocity = RealVelocity;
|
||||||
}
|
}
|
||||||
|
@ -3421,12 +3456,12 @@ void UVRCharacterMovementComponent::PhysSwimming(float deltaTime, int32 Iteratio
|
||||||
|
|
||||||
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && !bJustTeleported && ((deltaTime - remainingTime) > UE_KINDA_SMALL_NUMBER) && CharacterOwner)
|
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && !bJustTeleported && ((deltaTime - remainingTime) > UE_KINDA_SMALL_NUMBER) && CharacterOwner)
|
||||||
{
|
{
|
||||||
bool bWaterJump = !GetPhysicsVolume()->bWaterVolume;
|
const bool bWaterJump = !GetPhysicsVolume()->bWaterVolume;
|
||||||
float velZ = Velocity.Z;
|
const FVector::FReal VelZ = GetGravitySpaceZ(Velocity);
|
||||||
Velocity = ((UpdatedComponent->GetComponentLocation() - OldLocation)/* - AdditionalVRInputVector*/) / (deltaTime - remainingTime);
|
Velocity = ((UpdatedComponent->GetComponentLocation() - OldLocation)/* - AdditionalVRInputVector*/) / (deltaTime - remainingTime);
|
||||||
if (bWaterJump)
|
if (bWaterJump)
|
||||||
{
|
{
|
||||||
Velocity.Z = velZ;
|
SetGravitySpaceZ(Velocity, VelZ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3472,9 +3507,10 @@ void UVRCharacterMovementComponent::StartSwimmingVR(FVector OldLocation, FVector
|
||||||
}
|
}
|
||||||
MoveUpdatedComponent(End - NewLocation, UpdatedComponent->GetComponentQuat(), true);
|
MoveUpdatedComponent(End - NewLocation, UpdatedComponent->GetComponentQuat(), true);
|
||||||
}
|
}
|
||||||
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && (Velocity.Z > 2.f* CharacterMovementConstants::SWIMBOBSPEEDVR) && (Velocity.Z < 0.f)) //allow for falling out of water
|
const FVector::FReal GravityRelativeVelocityZ = GetGravitySpaceZ(Velocity);
|
||||||
|
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && (GravityRelativeVelocityZ > 2.f * CharacterMovementConstants::SWIMBOBSPEEDVR) && (GravityRelativeVelocityZ < 0.f)) //allow for falling out of water
|
||||||
{
|
{
|
||||||
Velocity.Z = CharacterMovementConstants::SWIMBOBSPEEDVR - Velocity.Size2D() * 0.7f; //smooth bobbing
|
SetGravitySpaceZ(Velocity, CharacterMovementConstants::SWIMBOBSPEEDVR - ProjectToGravityFloor(Velocity).Size() * 0.7f); //smooth bobbing
|
||||||
}
|
}
|
||||||
if ((remainingTime >= MIN_TICK_TIME) && (Iterations < MaxSimulationIterations))
|
if ((remainingTime >= MIN_TICK_TIME) && (Iterations < MaxSimulationIterations))
|
||||||
{
|
{
|
||||||
|
@ -3517,26 +3553,25 @@ bool UVRCharacterMovementComponent::CheckWaterJump(FVector CheckPoint, FVector&
|
||||||
FVector currentLoc = VRRootCapsule ? VRRootCapsule->OffsetComponentToWorld.GetLocation() : UpdatedComponent->GetComponentLocation();
|
FVector currentLoc = VRRootCapsule ? VRRootCapsule->OffsetComponentToWorld.GetLocation() : UpdatedComponent->GetComponentLocation();
|
||||||
|
|
||||||
// check if there is a wall directly in front of the swimming pawn
|
// check if there is a wall directly in front of the swimming pawn
|
||||||
CheckPoint.Z = 0.f;
|
CheckPoint = ProjectToGravityFloor(CheckPoint);
|
||||||
FVector CheckNorm = CheckPoint.GetSafeNormal();
|
FVector CheckNorm = CheckPoint.GetSafeNormal();
|
||||||
float PawnCapsuleRadius, PawnCapsuleHalfHeight;
|
float PawnCapsuleRadius, PawnCapsuleHalfHeight;
|
||||||
CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnCapsuleRadius, PawnCapsuleHalfHeight);
|
CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnCapsuleRadius, PawnCapsuleHalfHeight);
|
||||||
CheckPoint = currentLoc + 1.2f * PawnCapsuleRadius * CheckNorm;
|
CheckPoint = currentLoc + 1.2f * PawnCapsuleRadius * CheckNorm;
|
||||||
FVector Extent(PawnCapsuleRadius, PawnCapsuleRadius, PawnCapsuleHalfHeight);
|
|
||||||
FHitResult HitInfo(1.f);
|
FHitResult HitInfo(1.f);
|
||||||
FCollisionQueryParams CapsuleParams(SCENE_QUERY_STAT(CheckWaterJump), false, CharacterOwner);
|
FCollisionQueryParams CapsuleParams(SCENE_QUERY_STAT(CheckWaterJump), false, CharacterOwner);
|
||||||
FCollisionResponseParams ResponseParam;
|
FCollisionResponseParams ResponseParam;
|
||||||
InitCollisionParams(CapsuleParams, ResponseParam);
|
InitCollisionParams(CapsuleParams, ResponseParam);
|
||||||
FCollisionShape CapsuleShape = GetPawnCapsuleCollisionShape(SHRINK_None);
|
FCollisionShape CapsuleShape = GetPawnCapsuleCollisionShape(SHRINK_None);
|
||||||
const ECollisionChannel CollisionChannel = UpdatedComponent->GetCollisionObjectType();
|
const ECollisionChannel CollisionChannel = UpdatedComponent->GetCollisionObjectType();
|
||||||
bool bHit = GetWorld()->SweepSingleByChannel(HitInfo, currentLoc, CheckPoint, FQuat::Identity, CollisionChannel, CapsuleShape, CapsuleParams, ResponseParam);
|
bool bHit = GetWorld()->SweepSingleByChannel(HitInfo, UpdatedComponent->GetComponentLocation(), CheckPoint, GetWorldToGravityTransform(), CollisionChannel, CapsuleShape, CapsuleParams, ResponseParam);
|
||||||
|
|
||||||
if (bHit && !HitInfo.HitObjectHandle.DoesRepresentClass(APawn::StaticClass()))
|
if (bHit && !HitInfo.HitObjectHandle.DoesRepresentClass(APawn::StaticClass()))
|
||||||
{
|
{
|
||||||
// hit a wall - check if it is low enough
|
// hit a wall - check if it is low enough
|
||||||
WallNormal = -1.f * HitInfo.ImpactNormal;
|
WallNormal = -1.f * HitInfo.ImpactNormal;
|
||||||
FVector Start = currentLoc;//UpdatedComponent->GetComponentLocation();
|
FVector Start = currentLoc;//UpdatedComponent->GetComponentLocation();
|
||||||
Start.Z += MaxOutOfWaterStepHeight;
|
Start += MaxOutOfWaterStepHeight * -GetGravityDirection();
|
||||||
CheckPoint = Start + 3.2f * PawnCapsuleRadius * WallNormal;
|
CheckPoint = Start + 3.2f * PawnCapsuleRadius * WallNormal;
|
||||||
FCollisionQueryParams LineParams(SCENE_QUERY_STAT(CheckWaterJump), true, CharacterOwner);
|
FCollisionQueryParams LineParams(SCENE_QUERY_STAT(CheckWaterJump), true, CharacterOwner);
|
||||||
FCollisionResponseParams LineResponseParam;
|
FCollisionResponseParams LineResponseParam;
|
||||||
|
@ -3725,11 +3760,7 @@ void UVRCharacterMovementComponent::SimulateMovement(float DeltaSeconds)
|
||||||
// find floor and check if falling
|
// find floor and check if falling
|
||||||
if (IsMovingOnGround() || MovementMode == MOVE_Falling)
|
if (IsMovingOnGround() || MovementMode == MOVE_Falling)
|
||||||
{
|
{
|
||||||
bool bShouldFindFloor = Velocity.Z <= 0.f;
|
const bool bShouldFindFloor = GetGravitySpaceZ(Velocity) <= UE_KINDA_SMALL_NUMBER;
|
||||||
if (HasCustomGravity())
|
|
||||||
{
|
|
||||||
bShouldFindFloor = RotateWorldToGravity(Velocity).Z <= 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StepDownResult.bComputedFloor)
|
if (StepDownResult.bComputedFloor)
|
||||||
{
|
{
|
||||||
|
@ -3750,14 +3781,8 @@ void UVRCharacterMovementComponent::SimulateMovement(float DeltaSeconds)
|
||||||
{
|
{
|
||||||
// Follows PhysWalking approach for encroachment on floor tests
|
// Follows PhysWalking approach for encroachment on floor tests
|
||||||
FHitResult Hit(CurrentFloor.HitResult);
|
FHitResult Hit(CurrentFloor.HitResult);
|
||||||
if (HasCustomGravity())
|
|
||||||
{
|
|
||||||
Hit.TraceEnd = Hit.TraceStart - GetGravityDirection() * MAX_FLOOR_DIST;
|
Hit.TraceEnd = Hit.TraceStart - GetGravityDirection() * MAX_FLOOR_DIST;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Hit.TraceEnd = Hit.TraceStart + FVector(0.f, 0.f, MAX_FLOOR_DIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
const FVector RequestedAdjustment = GetPenetrationAdjustment(Hit);
|
const FVector RequestedAdjustment = GetPenetrationAdjustment(Hit);
|
||||||
const bool bResolved = ResolvePenetration(RequestedAdjustment, Hit, UpdatedComponent->GetComponentQuat());
|
const bool bResolved = ResolvePenetration(RequestedAdjustment, Hit, UpdatedComponent->GetComponentQuat());
|
||||||
|
@ -3775,18 +3800,11 @@ void UVRCharacterMovementComponent::SimulateMovement(float DeltaSeconds)
|
||||||
if (!bSimGravityDisabled)
|
if (!bSimGravityDisabled)
|
||||||
{
|
{
|
||||||
// No floor, must fall.
|
// No floor, must fall.
|
||||||
if (HasCustomGravity())
|
if (GetGravitySpaceZ(Velocity) <= UE_KINDA_SMALL_NUMBER || bApplyGravityWhileJumping || !CharacterOwner->IsJumpProvidingForce())
|
||||||
{
|
|
||||||
if (RotateWorldToGravity(Velocity).Z <= 0.f || bApplyGravityWhileJumping || !CharacterOwner->IsJumpProvidingForce())
|
|
||||||
{
|
{
|
||||||
Velocity = NewFallVelocity(Velocity, -GetGravityDirection() * GetGravityZ(), DeltaSeconds);
|
Velocity = NewFallVelocity(Velocity, -GetGravityDirection() * GetGravityZ(), DeltaSeconds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Velocity.Z <= 0.f || bApplyGravityWhileJumping || !CharacterOwner->IsJumpProvidingForce())
|
|
||||||
{
|
|
||||||
Velocity = NewFallVelocity(Velocity, FVector(0.f, 0.f, GetGravityZ()), DeltaSeconds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SetMovementMode(MOVE_Falling);
|
SetMovementMode(MOVE_Falling);
|
||||||
}
|
}
|
||||||
|
@ -3903,7 +3921,7 @@ void UVRCharacterMovementComponent::MoveSmooth(const FVector& InVelocity, const
|
||||||
{
|
{
|
||||||
OutStepDownResult = NULL; // No need for a floor when not walking.
|
OutStepDownResult = NULL; // No need for a floor when not walking.
|
||||||
bool bShouldAttemptStepUp = false;
|
bool bShouldAttemptStepUp = false;
|
||||||
bShouldAttemptStepUp = FMath::Abs(RotateWorldToGravity(Hit.ImpactNormal).Z) < 0.2;
|
bShouldAttemptStepUp = FMath::Abs(GetGravitySpaceZ(Hit.ImpactNormal)) < 0.2;
|
||||||
if (bShouldAttemptStepUp)
|
if (bShouldAttemptStepUp)
|
||||||
{
|
{
|
||||||
const FVector GravDir = GetGravityDirection();
|
const FVector GravDir = GetGravityDirection();
|
||||||
|
@ -3946,7 +3964,7 @@ void UVRCharacterMovementComponent::ClientHandleMoveResponse(const FCharacterMov
|
||||||
MoveResponse.RootMotionTrackPosition,
|
MoveResponse.RootMotionTrackPosition,
|
||||||
MoveResponse.ClientAdjustment.NewLoc,
|
MoveResponse.ClientAdjustment.NewLoc,
|
||||||
MoveResponse.RootMotionRotation,
|
MoveResponse.RootMotionRotation,
|
||||||
MoveResponse.ClientAdjustment.NewVel.Z,
|
GetGravitySpaceZ(MoveResponse.ClientAdjustment.NewVel),
|
||||||
MoveResponse.ClientAdjustment.NewBase,
|
MoveResponse.ClientAdjustment.NewBase,
|
||||||
MoveResponse.ClientAdjustment.NewBaseBoneName,
|
MoveResponse.ClientAdjustment.NewBaseBoneName,
|
||||||
MoveResponse.bHasBase,
|
MoveResponse.bHasBase,
|
||||||
|
@ -3961,7 +3979,7 @@ void UVRCharacterMovementComponent::ClientHandleMoveResponse(const FCharacterMov
|
||||||
MoveResponse.RootMotionTrackPosition,
|
MoveResponse.RootMotionTrackPosition,
|
||||||
MoveResponse.ClientAdjustment.NewLoc,
|
MoveResponse.ClientAdjustment.NewLoc,
|
||||||
MoveResponse.RootMotionRotation,
|
MoveResponse.RootMotionRotation,
|
||||||
MoveResponse.ClientAdjustment.NewVel.Z,
|
GetGravitySpaceZ(MoveResponse.ClientAdjustment.NewVel),
|
||||||
MoveResponse.ClientAdjustment.NewBase,
|
MoveResponse.ClientAdjustment.NewBase,
|
||||||
MoveResponse.ClientAdjustment.NewBaseBoneName,
|
MoveResponse.ClientAdjustment.NewBaseBoneName,
|
||||||
MoveResponse.bHasBase,
|
MoveResponse.bHasBase,
|
||||||
|
@ -4452,7 +4470,7 @@ void UVRCharacterMovementComponent::ServerMoveHandleClientErrorVR(float ClientTi
|
||||||
{
|
{
|
||||||
const FVector LastBaseVelocity = MovementBaseUtility::GetMovementBaseVelocity(LastServerMovementBaseVRPtr, LastServerMovementBaseBoneName);
|
const FVector LastBaseVelocity = MovementBaseUtility::GetMovementBaseVelocity(LastServerMovementBaseVRPtr, LastServerMovementBaseBoneName);
|
||||||
RelativeVelocity = Velocity - LastBaseVelocity;
|
RelativeVelocity = Velocity - LastBaseVelocity;
|
||||||
const FVector BaseDirection = LastBaseVelocity.GetSafeNormal2D();
|
const FVector BaseDirection = ProjectToGravityFloor(LastBaseVelocity).GetSafeNormal();
|
||||||
const FVector RelativeDirection = RelativeVelocity * (1.f / MaxWalkSpeed);
|
const FVector RelativeDirection = RelativeVelocity * (1.f / MaxWalkSpeed);
|
||||||
|
|
||||||
ClientForwardFactor = FMath::Clamp(FVector::DotProduct(BaseDirection, RelativeDirection), 0.f, 1.f);
|
ClientForwardFactor = FMath::Clamp(FVector::DotProduct(BaseDirection, RelativeDirection), 0.f, 1.f);
|
||||||
|
|
|
@ -245,7 +245,7 @@ void UVRGestureComponent::CaptureGestureFrame()
|
||||||
// Pop off oldest sample
|
// Pop off oldest sample
|
||||||
if (GestureLog.Samples.Num() >= RecordingBufferSize)
|
if (GestureLog.Samples.Num() >= RecordingBufferSize)
|
||||||
{
|
{
|
||||||
GestureLog.Samples.Pop(false);
|
GestureLog.Samples.Pop(EAllowShrinking::No);
|
||||||
bClearLatestSpline = true;
|
bClearLatestSpline = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,8 +600,8 @@ bool UGesturesDatabase::ImportSplineAsGesture(USplineComponent * HostSplineCompo
|
||||||
|
|
||||||
float LastDistance = 0.f;
|
float LastDistance = 0.f;
|
||||||
float ThisDistance = 0.f;
|
float ThisDistance = 0.f;
|
||||||
FVector LastDistanceV;
|
FVector LastDistanceV = FVector::ZeroVector;
|
||||||
FVector ThisDistanceV;
|
FVector ThisDistanceV = FVector::ZeroVector;
|
||||||
FVector DistNormal;
|
FVector DistNormal;
|
||||||
float DistAlongSegment = 0.f;
|
float DistAlongSegment = 0.f;
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
#include "VRPathFollowingComponent.h"
|
#include "VRPathFollowingComponent.h"
|
||||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(VRPathFollowingComponent)
|
#include UE_INLINE_GENERATED_CPP_BY_NAME(VRPathFollowingComponent)
|
||||||
|
|
||||||
|
#include "AI/Navigation/NavigationTypes.h"
|
||||||
|
#include "AI/Navigation/PathFollowingAgentInterface.h"
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "Engine/World.h"
|
#include "Engine/World.h"
|
||||||
//#include "Runtime/Engine/Private/EnginePrivate.h"
|
//#include "Runtime/Engine/Private/EnginePrivate.h"
|
||||||
|
@ -16,7 +19,7 @@
|
||||||
|
|
||||||
DEFINE_LOG_CATEGORY(LogPathFollowingVR);
|
DEFINE_LOG_CATEGORY(LogPathFollowingVR);
|
||||||
|
|
||||||
void UVRPathFollowingComponent::SetMovementComponent(UNavMovementComponent* MoveComp)
|
/*void UVRPathFollowingComponent::SetMovementComponent(UNavMovementComponent* MoveComp)
|
||||||
{
|
{
|
||||||
Super::SetMovementComponent(MoveComp);
|
Super::SetMovementComponent(MoveComp);
|
||||||
|
|
||||||
|
@ -26,8 +29,23 @@ void UVRPathFollowingComponent::SetMovementComponent(UNavMovementComponent* Move
|
||||||
{
|
{
|
||||||
OnRequestFinished.AddUObject(VRMovementComp, &UVRBaseCharacterMovementComponent::OnMoveCompleted);
|
OnRequestFinished.AddUObject(VRMovementComp, &UVRBaseCharacterMovementComponent::OnMoveCompleted);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
void UVRPathFollowingComponent::SetNavMovementInterface(INavMovementInterface* NavMoveInterface)
|
||||||
|
{
|
||||||
|
Super::SetNavMovementInterface(NavMoveInterface);
|
||||||
|
|
||||||
|
if (NavMovementInterface.IsValid() && NavMovementInterface->GetOwnerAsObject())
|
||||||
|
{
|
||||||
|
if (AVRBaseCharacter* VRMovement = Cast<AVRBaseCharacter>(NavMovementInterface->GetOwnerAsObject()))
|
||||||
|
{
|
||||||
|
if (IsValid(VRMovement->VRMovementReference))
|
||||||
|
{
|
||||||
|
OnRequestFinished.AddUObject(VRMovement->VRMovementReference, &UVRBaseCharacterMovementComponent::OnMoveCompleted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UVRPathFollowingComponent::GetDebugStringTokens(TArray<FString>& Tokens, TArray<EPathFollowingDebugTokens::Type>& Flags) const
|
void UVRPathFollowingComponent::GetDebugStringTokens(TArray<FString>& Tokens, TArray<EPathFollowingDebugTokens::Type>& Flags) const
|
||||||
{
|
{
|
||||||
|
@ -82,52 +100,8 @@ void UVRPathFollowingComponent::GetDebugStringTokens(TArray<FString>& Tokens, TA
|
||||||
Flags.Add(bFailedHeight ? EPathFollowingDebugTokens::FailedValue : EPathFollowingDebugTokens::PassedValue);
|
Flags.Add(bFailedHeight ? EPathFollowingDebugTokens::FailedValue : EPathFollowingDebugTokens::PassedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UVRPathFollowingComponent::PauseMove(FAIRequestID RequestID, EPathFollowingVelocityMode VelocityMode)
|
|
||||||
{
|
|
||||||
//UE_VLOG(GetOwner(), LogPathFollowing, Log, TEXT("PauseMove: RequestID(%u)"), RequestID);
|
|
||||||
if (Status == EPathFollowingStatus::Paused)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RequestID.IsEquivalent(GetCurrentRequestId()))
|
/*int32 UVRPathFollowingComponent::DetermineStartingPathPoint(const FNavigationPath* ConsideredPath) const
|
||||||
{
|
|
||||||
if ((VelocityMode == EPathFollowingVelocityMode::Reset) && MovementComp && HasMovementAuthority())
|
|
||||||
{
|
|
||||||
MovementComp->StopMovementKeepPathing();
|
|
||||||
}
|
|
||||||
|
|
||||||
LocationWhenPaused = MovementComp ? (VRMovementComp != nullptr ? VRMovementComp->GetActorFeetLocationVR() : MovementComp->GetActorFeetLocation()) : FVector::ZeroVector;
|
|
||||||
PathTimeWhenPaused = Path.IsValid() ? Path->GetTimeStamp() : 0.;
|
|
||||||
Status = EPathFollowingStatus::Paused;
|
|
||||||
|
|
||||||
UpdateMoveFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool UVRPathFollowingComponent::ShouldCheckPathOnResume() const
|
|
||||||
{
|
|
||||||
bool bCheckPath = true;
|
|
||||||
if (MovementComp != NULL)
|
|
||||||
{
|
|
||||||
float AgentRadius = 0.0f, AgentHalfHeight = 0.0f;
|
|
||||||
MovementComp->GetOwner()->GetSimpleCollisionCylinder(AgentRadius, AgentHalfHeight);
|
|
||||||
|
|
||||||
const FVector CurrentLocation = (VRMovementComp != nullptr ? VRMovementComp->GetActorFeetLocation() : MovementComp->GetActorFeetLocation());
|
|
||||||
const FVector::FReal DeltaMove2DSq = (CurrentLocation - LocationWhenPaused).SizeSquared2D();
|
|
||||||
const FVector::FReal DeltaZ = FMath::Abs(CurrentLocation.Z - LocationWhenPaused.Z);
|
|
||||||
if (DeltaMove2DSq < FMath::Square(AgentRadius) && DeltaZ < (AgentHalfHeight * 0.5))
|
|
||||||
{
|
|
||||||
bCheckPath = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bCheckPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 UVRPathFollowingComponent::DetermineStartingPathPoint(const FNavigationPath* ConsideredPath) const
|
|
||||||
{
|
{
|
||||||
int32 PickedPathPoint = INDEX_NONE;
|
int32 PickedPathPoint = INDEX_NONE;
|
||||||
|
|
||||||
|
@ -302,8 +276,8 @@ void UVRPathFollowingComponent::UpdatePathSegment()
|
||||||
if (Path->GetPathPoints().IsValidIndex(MoveSegmentEndIndex) && Path->GetPathPoints().IsValidIndex(MoveSegmentStartIndex))
|
if (Path->GetPathPoints().IsValidIndex(MoveSegmentEndIndex) && Path->GetPathPoints().IsValidIndex(MoveSegmentStartIndex))
|
||||||
{
|
{
|
||||||
//LogBlockHelper(GetOwner(), MovementComp, MinAgentRadiusPct, MinAgentHalfHeightPct,
|
//LogBlockHelper(GetOwner(), MovementComp, MinAgentRadiusPct, MinAgentHalfHeightPct,
|
||||||
//*Path->GetPathPointLocation(MoveSegmentStartIndex),
|
//Path->GetPathPointLocation(MoveSegmentStartIndex),
|
||||||
//*Path->GetPathPointLocation(MoveSegmentEndIndex));
|
//Path->GetPathPointLocation(MoveSegmentEndIndex));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -455,7 +429,7 @@ void UVRPathFollowingComponent::DebugReachTest(float& CurrentDot, float& Current
|
||||||
|
|
||||||
const FVector ToGoal = (GoalLocation - AgentLocation);
|
const FVector ToGoal = (GoalLocation - AgentLocation);
|
||||||
const FVector CurrentDirection = GetCurrentDirection();
|
const FVector CurrentDirection = GetCurrentDirection();
|
||||||
CurrentDot = FloatCastChecked<float>(FVector::DotProduct(ToGoal.GetSafeNormal(), CurrentDirection), /* Precision */ 1. / 128.);
|
CurrentDot = FloatCastChecked<float>(FVector::DotProduct(ToGoal.GetSafeNormal(), CurrentDirection), 1. / 128.);
|
||||||
bDotFailed = (CurrentDot < 0.0f) ? 1 : 0;
|
bDotFailed = (CurrentDot < 0.0f) ? 1 : 0;
|
||||||
|
|
||||||
// get cylinder of moving agent
|
// get cylinder of moving agent
|
||||||
|
@ -472,3 +446,4 @@ void UVRPathFollowingComponent::DebugReachTest(float& CurrentDot, float& Current
|
||||||
const float UseHeight = GoalHalfHeight + (AgentHalfHeight * MinAgentHalfHeightPct);
|
const float UseHeight = GoalHalfHeight + (AgentHalfHeight * MinAgentHalfHeightPct);
|
||||||
bHeightFailed = (CurrentHeight > UseHeight) ? 1 : 0;
|
bHeightFailed = (CurrentHeight > UseHeight) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
*/
|
|
@ -862,8 +862,12 @@ public:
|
||||||
{
|
{
|
||||||
bWillEverBeLit = false;
|
bWillEverBeLit = false;
|
||||||
bCreateSceneProxy = InComponent->bShouldCreateProxy;
|
bCreateSceneProxy = InComponent->bShouldCreateProxy;
|
||||||
|
|
||||||
|
if (MaterialInstance)
|
||||||
|
{
|
||||||
MaterialRelevance = MaterialInstance->GetRelevance(GetScene().GetFeatureLevel());
|
MaterialRelevance = MaterialInstance->GetRelevance(GetScene().GetFeatureLevel());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FPrimitiveSceneProxy interface.
|
// FPrimitiveSceneProxy interface.
|
||||||
virtual void GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const override
|
virtual void GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const override
|
||||||
|
@ -886,12 +890,12 @@ public:
|
||||||
{
|
{
|
||||||
ParentMaterialProxy = WireframeMaterialInstance;
|
ParentMaterialProxy = WireframeMaterialInstance;
|
||||||
}
|
}
|
||||||
else
|
else if (MaterialInstance != nullptr)
|
||||||
{
|
{
|
||||||
ParentMaterialProxy = MaterialInstance->GetRenderProxy();
|
ParentMaterialProxy = MaterialInstance->GetRenderProxy();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
FMaterialRenderProxy* ParentMaterialProxy = MaterialInstance->GetRenderProxy();
|
FMaterialRenderProxy* ParentMaterialProxy = MaterialInstance ? MaterialInstance->GetRenderProxy() : nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//FSpriteTextureOverrideRenderProxy* TextureOverrideMaterialProxy = new FSpriteTextureOverrideRenderProxy(ParentMaterialProxy,
|
//FSpriteTextureOverrideRenderProxy* TextureOverrideMaterialProxy = new FSpriteTextureOverrideRenderProxy(ParentMaterialProxy,
|
||||||
|
@ -912,10 +916,10 @@ public:
|
||||||
{
|
{
|
||||||
if (GeometryMode == EWidgetGeometryMode::Plane)
|
if (GeometryMode == EWidgetGeometryMode::Plane)
|
||||||
{
|
{
|
||||||
float U = -RenderTarget->SizeX * Pivot.X;
|
float U = -RenderTarget->SizeX * static_cast<float>(Pivot.X);
|
||||||
float V = -RenderTarget->SizeY * Pivot.Y;
|
float V = -RenderTarget->SizeY * static_cast<float>(Pivot.Y);
|
||||||
float UL = RenderTarget->SizeX * (1.0f - Pivot.X);
|
float UL = RenderTarget->SizeX * (1.0f - static_cast<float>(Pivot.X));
|
||||||
float VL = RenderTarget->SizeY * (1.0f - Pivot.Y);
|
float VL = RenderTarget->SizeY * (1.0f - static_cast<float>(Pivot.Y));
|
||||||
|
|
||||||
int32 VertexIndices[4];
|
int32 VertexIndices[4];
|
||||||
|
|
||||||
|
@ -948,13 +952,13 @@ public:
|
||||||
const int32 NumSegments = FMath::Lerp(4, 32, ArcAngle / PI);
|
const int32 NumSegments = FMath::Lerp(4, 32, ArcAngle / PI);
|
||||||
|
|
||||||
|
|
||||||
const float Radius = RenderTarget->SizeX / ArcAngle;
|
const double Radius = RenderTarget->SizeX / ArcAngle;
|
||||||
const float Apothem = Radius * FMath::Cos(0.5f*ArcAngle);
|
const double Apothem = Radius * FMath::Cos(0.5 * ArcAngle);
|
||||||
const float ChordLength = 2.0f * Radius * FMath::Sin(0.5f*ArcAngle);
|
const double ChordLength = 2.0f * Radius * FMath::Sin(0.5 * ArcAngle);
|
||||||
|
|
||||||
const float PivotOffsetX = ChordLength * (0.5 - Pivot.X);
|
const double PivotOffsetX = ChordLength * (0.5 - Pivot.X);
|
||||||
const float V = -RenderTarget->SizeY * Pivot.Y;
|
const double V = -RenderTarget->SizeY * Pivot.Y;
|
||||||
const float VL = RenderTarget->SizeY * (1.0f - Pivot.Y);
|
const double VL = RenderTarget->SizeY * (1.0 - Pivot.Y);
|
||||||
|
|
||||||
int32 VertexIndices[4];
|
int32 VertexIndices[4];
|
||||||
|
|
||||||
|
@ -964,7 +968,7 @@ public:
|
||||||
|
|
||||||
if (VisibilityMap & (1 << ViewIndex))
|
if (VisibilityMap & (1 << ViewIndex))
|
||||||
{
|
{
|
||||||
const float RadiansPerStep = ArcAngle / NumSegments;
|
const double RadiansPerStep = ArcAngle / NumSegments;
|
||||||
|
|
||||||
FVector LastTangentX;
|
FVector LastTangentX;
|
||||||
FVector LastTangentY;
|
FVector LastTangentY;
|
||||||
|
@ -972,14 +976,14 @@ public:
|
||||||
|
|
||||||
for (int32 Segment = 0; Segment < NumSegments; Segment++)
|
for (int32 Segment = 0; Segment < NumSegments; Segment++)
|
||||||
{
|
{
|
||||||
const float Angle = -ArcAngle / 2 + Segment * RadiansPerStep;
|
const double Angle = -ArcAngle / 2 + Segment * RadiansPerStep;
|
||||||
const float NextAngle = Angle + RadiansPerStep;
|
const double NextAngle = Angle + RadiansPerStep;
|
||||||
|
|
||||||
// Polar to Cartesian
|
// Polar to Cartesian
|
||||||
const float X0 = Radius * FMath::Cos(Angle) - Apothem;
|
const double X0 = Radius * FMath::Cos(Angle) - Apothem;
|
||||||
const float Y0 = Radius * FMath::Sin(Angle);
|
const double Y0 = Radius * FMath::Sin(Angle);
|
||||||
const float X1 = Radius * FMath::Cos(NextAngle) - Apothem;
|
const double X1 = Radius * FMath::Cos(NextAngle) - Apothem;
|
||||||
const float Y1 = Radius * FMath::Sin(NextAngle);
|
const double Y1 = Radius * FMath::Sin(NextAngle);
|
||||||
|
|
||||||
const float U0 = static_cast<float>(Segment) / NumSegments;
|
const float U0 = static_cast<float>(Segment) / NumSegments;
|
||||||
const float U1 = static_cast<float>(Segment + 1) / NumSegments;
|
const float U1 = static_cast<float>(Segment + 1) / NumSegments;
|
||||||
|
@ -1123,7 +1127,7 @@ public:
|
||||||
|
|
||||||
virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); }
|
virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); }
|
||||||
|
|
||||||
uint32 GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
|
SIZE_T GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FVector Origin;
|
FVector Origin;
|
||||||
|
@ -1135,7 +1139,7 @@ private:
|
||||||
UBodySetup* BodySetup;
|
UBodySetup* BodySetup;
|
||||||
EWidgetBlendMode BlendMode;
|
EWidgetBlendMode BlendMode;
|
||||||
EWidgetGeometryMode GeometryMode;
|
EWidgetGeometryMode GeometryMode;
|
||||||
float ArcAngle;
|
double ArcAngle;
|
||||||
bool bCreateSceneProxy;
|
bool bCreateSceneProxy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1148,11 +1152,14 @@ FPrimitiveSceneProxy* UVRStereoWidgetComponent::CreateSceneProxy()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WidgetRenderer && GetSlateWindow() && GetSlateWindow()->GetContent() != SNullWidget::NullWidget)
|
if (WidgetRenderer && GetSlateWindow() && GetSlateWindow()->GetContent() != SNullWidget::NullWidget)
|
||||||
|
{
|
||||||
|
if (ISlate3DRenderer* SlateRenderer = WidgetRenderer->GetSlateRenderer())
|
||||||
{
|
{
|
||||||
RequestRenderUpdate();
|
RequestRenderUpdate();
|
||||||
LastWidgetRenderTime = 0;
|
LastWidgetRenderTime = 0;
|
||||||
|
|
||||||
return new FStereoWidget3DSceneProxy(this, *WidgetRenderer->GetSlateRenderer());
|
return new FStereoWidget3DSceneProxy(this, *SlateRenderer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if WITH_EDITOR
|
#if WITH_EDITOR
|
||||||
|
@ -1208,7 +1215,7 @@ FPrimitiveSceneProxy* UVRStereoWidgetComponent::CreateSceneProxy()
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); }
|
virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); }
|
||||||
uint32 GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
|
SIZE_T GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const FVector BoxExtents;
|
const FVector BoxExtents;
|
||||||
|
|
|
@ -88,7 +88,7 @@ public:
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
uint8 MoveActionFlags;
|
uint8 MoveActionFlags;
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
TArray<UObject*> MoveActionObjectReferences;
|
TArray<TObjectPtr<UObject>> MoveActionObjectReferences;
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
EVRMoveActionVelocityRetention VelRetentionSetting;
|
EVRMoveActionVelocityRetention VelRetentionSetting;
|
||||||
|
|
||||||
|
@ -516,7 +516,7 @@ public:
|
||||||
|
|
||||||
// Moved these here to avoid having to duplicate tons of properties
|
// Moved these here to avoid having to duplicate tons of properties
|
||||||
UPROPERTY(Transient)
|
UPROPERTY(Transient)
|
||||||
UPrimitiveComponent* ClientMovementBase;
|
TObjectPtr<UPrimitiveComponent> ClientMovementBase;
|
||||||
UPROPERTY(Transient)
|
UPROPERTY(Transient)
|
||||||
FName ClientBaseBoneName;
|
FName ClientBaseBoneName;
|
||||||
|
|
||||||
|
|
|
@ -809,7 +809,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadWrite, Category = "GripMotionController")
|
UPROPERTY(BlueprintReadWrite, Category = "GripMotionController")
|
||||||
TArray<UPrimitiveComponent *> AdditionalLateUpdateComponents;
|
TArray<TObjectPtr<UPrimitiveComponent>> AdditionalLateUpdateComponents;
|
||||||
|
|
||||||
// Movement Replication
|
// Movement Replication
|
||||||
// Actor needs to be replicated for this to work
|
// Actor needs to be replicated for this to work
|
||||||
|
|
|
@ -64,8 +64,11 @@ private:
|
||||||
TMap<Chaos::FConstPhysicsObjectHandle, FReplicatedPhysicsTargetAsync> ObjectToTarget;
|
TMap<Chaos::FConstPhysicsObjectHandle, FReplicatedPhysicsTargetAsync> ObjectToTarget;
|
||||||
TMap<Chaos::FConstPhysicsObjectHandle, FNetworkPhysicsSettingsAsync> ObjectToSettings;
|
TMap<Chaos::FConstPhysicsObjectHandle, FNetworkPhysicsSettingsAsync> ObjectToSettings;
|
||||||
TArray<int32> ParticlesInResimIslands;
|
TArray<int32> ParticlesInResimIslands;
|
||||||
|
TArray<Chaos::FParticleID> ReplicatedParticleIDs;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
FReplicatedPhysicsTargetAsync* AddObjectToReplication(Chaos::FConstPhysicsObjectHandle PhysicsObject);
|
||||||
|
void RemoveObjectFromReplication(Chaos::FConstPhysicsObjectHandle PhysicsObject);
|
||||||
void UpdateAsyncTarget(const FPhysicsRepAsyncInputData& Input, Chaos::FPBDRigidsSolver* RigidsSolver);
|
void UpdateAsyncTarget(const FPhysicsRepAsyncInputData& Input, Chaos::FPBDRigidsSolver* RigidsSolver);
|
||||||
void UpdateRewindDataTarget(const FPhysicsRepAsyncInputData& Input);
|
void UpdateRewindDataTarget(const FPhysicsRepAsyncInputData& Input);
|
||||||
void CacheResimInteractions();
|
void CacheResimInteractions();
|
||||||
|
@ -105,6 +108,7 @@ public:
|
||||||
TArray<FReplicatedPhysicsTarget> ReplicatedTargetsQueueVR;
|
TArray<FReplicatedPhysicsTarget> ReplicatedTargetsQueueVR;
|
||||||
FPhysicsReplicationAsyncVR* PhysicsReplicationAsyncVR;
|
FPhysicsReplicationAsyncVR* PhysicsReplicationAsyncVR;
|
||||||
FPhysicsReplicationAsyncInput* AsyncInputVR; //async data being written into before we push into callback
|
FPhysicsReplicationAsyncInput* AsyncInputVR; //async data being written into before we push into callback
|
||||||
|
TWeakObjectPtr<UNetworkPhysicsSettingsComponent> SettingsCurrent;
|
||||||
|
|
||||||
void PrepareAsyncData_ExternalVR(const FRigidBodyErrorCorrection& ErrorCorrection); //prepare async data for writing. Call on external thread (i.e. game thread)
|
void PrepareAsyncData_ExternalVR(const FRigidBodyErrorCorrection& ErrorCorrection); //prepare async data for writing. Call on external thread (i.e. game thread)
|
||||||
};
|
};
|
||||||
|
|
|
@ -113,7 +113,7 @@ struct FAISightTargetVR
|
||||||
static const FTargetId InvalidTargetId;
|
static const FTargetId InvalidTargetId;
|
||||||
|
|
||||||
TWeakObjectPtr<AActor> Target;
|
TWeakObjectPtr<AActor> Target;
|
||||||
IAISightTargetInterface* SightTargetInterface;
|
TWeakInterfacePtr<IAISightTargetInterface> WeakSightTargetInterface;
|
||||||
FGenericTeamId TeamId;
|
FGenericTeamId TeamId;
|
||||||
FTargetId TargetId;
|
FTargetId TargetId;
|
||||||
|
|
||||||
|
@ -333,7 +333,7 @@ protected:
|
||||||
FOnPendingVisibilityQueryProcessedDelegateVR OnPendingCanBeSeenQueryProcessedDelegate;
|
FOnPendingVisibilityQueryProcessedDelegateVR OnPendingCanBeSeenQueryProcessedDelegate;
|
||||||
FTraceDelegate OnPendingTraceQueryProcessedDelegate;
|
FTraceDelegate OnPendingTraceQueryProcessedDelegate;
|
||||||
|
|
||||||
UE_MT_DECLARE_RW_ACCESS_DETECTOR(QueriesListAccessDetector);
|
UE_MT_DECLARE_TS_RW_ACCESS_DETECTOR(QueriesListAccessDetector);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -28,17 +28,21 @@ public:
|
||||||
void SetConstraintToForceBased(bool bUseForceConstraint)
|
void SetConstraintToForceBased(bool bUseForceConstraint)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!ConstraintInstance.ConstraintHandle.IsValid())
|
// #TODO: Double check on this in 5.5, but it should work
|
||||||
|
this->SetLinearDriveAccelerationMode(!bUseForceConstraint);
|
||||||
|
this->SetAngularDriveAccelerationMode(!bUseForceConstraint);
|
||||||
|
/*if (!ConstraintInstance.ConstraintHandle.IsValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ConstraintInstance.ConstraintHandle->IsType(Chaos::EConstraintType::JointConstraintType))
|
if (ConstraintInstance.ConstraintHandle->IsType(Chaos::EConstraintType::JointConstraintType))
|
||||||
{
|
{
|
||||||
|
|
||||||
if (Chaos::FJointConstraint* Constraint = static_cast<Chaos::FJointConstraint*>(ConstraintInstance.ConstraintHandle.Constraint))
|
if (Chaos::FJointConstraint* Constraint = static_cast<Chaos::FJointConstraint*>(ConstraintInstance.ConstraintHandle.Constraint))
|
||||||
{
|
{
|
||||||
Constraint->SetLinearDriveForceMode(bUseForceConstraint ? Chaos::EJointForceMode::Force : Chaos::EJointForceMode::Acceleration);
|
Constraint->SetLinearDriveForceMode(bUseForceConstraint ? Chaos::EJointForceMode::Force : Chaos::EJointForceMode::Acceleration);
|
||||||
Constraint->SetAngularDriveForceMode(bUseForceConstraint ? Chaos::EJointForceMode::Force : Chaos::EJointForceMode::Acceleration);
|
Constraint->SetAngularDriveForceMode(bUseForceConstraint ? Chaos::EJointForceMode::Force : Chaos::EJointForceMode::Acceleration);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
//#endif
|
//#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -388,7 +388,7 @@ public:
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
UPROPERTY(VisibleAnywhere, Instanced, NoClear, Category = "User Interface", meta = (ShowOnlyInnerProperties))
|
UPROPERTY(VisibleAnywhere, Instanced, NoClear, Category = "User Interface", meta = (ShowOnlyInnerProperties))
|
||||||
UVRFullScreenUserWidget* ScreenUserWidget;
|
TObjectPtr<UVRFullScreenUserWidget> ScreenUserWidget;
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable, Category = "FullScreenWidgetActor")
|
UFUNCTION(BlueprintCallable, Category = "FullScreenWidgetActor")
|
||||||
UVRFullScreenUserWidget* GetPreviewWidgetComp();
|
UVRFullScreenUserWidget* GetPreviewWidgetComp();
|
||||||
|
|
|
@ -175,7 +175,7 @@ protected:
|
||||||
int numMessages = OutMessages.Num();
|
int numMessages = OutMessages.Num();
|
||||||
if (numMessages > MaxStoredMessages)
|
if (numMessages > MaxStoredMessages)
|
||||||
{
|
{
|
||||||
OutMessages.RemoveAt(0, numMessages - MaxStoredMessages, true);
|
OutMessages.RemoveAt(0, numMessages - MaxStoredMessages, EAllowShrinking::Yes);
|
||||||
}
|
}
|
||||||
if (OldNumMessages != numMessages)
|
if (OldNumMessages != numMessages)
|
||||||
bIsDirty = true;
|
bIsDirty = true;
|
||||||
|
|
|
@ -13,6 +13,40 @@
|
||||||
#include "VRWheeledVehicle.generated.h"
|
#include "VRWheeledVehicle.generated.h"
|
||||||
|
|
||||||
|
|
||||||
|
// This only exists to expose the blueprint properties of the transmission values
|
||||||
|
USTRUCT(BlueprintType, Category = "VRWheeledVehicle")
|
||||||
|
struct VREXPANSIONPLUGIN_API FBPVehicleTransmissionConfig : public FVehicleTransmissionConfig
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
public:
|
||||||
|
|
||||||
|
void SetFrom(FVehicleTransmissionConfig & Config)
|
||||||
|
{
|
||||||
|
bUseAutomaticGears = Config.bUseAutomaticGears;
|
||||||
|
bUseAutoReverse = Config.bUseAutoReverse;
|
||||||
|
FinalRatio = Config.FinalRatio;
|
||||||
|
ForwardGearRatios = Config.ForwardGearRatios;
|
||||||
|
ReverseGearRatios = Config.ReverseGearRatios;
|
||||||
|
ChangeUpRPM = Config.ChangeUpRPM;
|
||||||
|
ChangeDownRPM = Config.ChangeDownRPM;
|
||||||
|
GearChangeTime = Config.GearChangeTime;
|
||||||
|
TransmissionEfficiency = Config.TransmissionEfficiency;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTo(FVehicleTransmissionConfig& Config)
|
||||||
|
{
|
||||||
|
Config.bUseAutomaticGears = bUseAutomaticGears;
|
||||||
|
Config.bUseAutoReverse = bUseAutoReverse;
|
||||||
|
Config.FinalRatio = FinalRatio;
|
||||||
|
Config.ForwardGearRatios = ForwardGearRatios;
|
||||||
|
Config.ReverseGearRatios = ReverseGearRatios;
|
||||||
|
Config.ChangeUpRPM = ChangeUpRPM;
|
||||||
|
Config.ChangeDownRPM = ChangeDownRPM;
|
||||||
|
Config.GearChangeTime = GearChangeTime;
|
||||||
|
Config.TransmissionEfficiency = TransmissionEfficiency;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This override of the base wheeled vehicle allows for dual pawn usage in engine.
|
* This override of the base wheeled vehicle allows for dual pawn usage in engine.
|
||||||
*/
|
*/
|
||||||
|
@ -24,6 +58,29 @@ class VREXPANSIONPLUGIN_API AVRWheeledVehicle : public AWheeledVehiclePawn
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintPure, Category = "Pawn")
|
||||||
|
float GetFinalGearRatio()
|
||||||
|
{
|
||||||
|
float CurrentGearRatio = 0.0f;
|
||||||
|
if (UChaosWheeledVehicleMovementComponent* MoveComp = Cast<UChaosWheeledVehicleMovementComponent>(this->GetMovementComponent()))
|
||||||
|
{
|
||||||
|
CurrentGearRatio = MoveComp->TransmissionSetup.FinalRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CurrentGearRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Pawn")
|
||||||
|
void SetFinalGearRatio(float NewFinalGearRatio)
|
||||||
|
{
|
||||||
|
if (UChaosWheeledVehicleMovementComponent* MoveComp = Cast<UChaosWheeledVehicleMovementComponent>(this->GetMovementComponent()))
|
||||||
|
{
|
||||||
|
MoveComp->TransmissionSetup.FinalRatio = NewFinalGearRatio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calls the movement components override controller function
|
||||||
UFUNCTION(BlueprintCallable, Category = "Pawn")
|
UFUNCTION(BlueprintCallable, Category = "Pawn")
|
||||||
virtual bool SetBindToInput(AController * CController, bool bBindToInput)
|
virtual bool SetBindToInput(AController * CController, bool bBindToInput)
|
||||||
{
|
{
|
||||||
|
|
|
@ -101,7 +101,7 @@ public:
|
||||||
|
|
||||||
// Get Camera View is no longer required, they finally broke the HMD logic out into its own section!!
|
// Get Camera View is no longer required, they finally broke the HMD logic out into its own section!!
|
||||||
//virtual void GetCameraView(float DeltaTime, FMinimalViewInfo& DesiredView) override;
|
//virtual void GetCameraView(float DeltaTime, FMinimalViewInfo& DesiredView) override;
|
||||||
virtual void HandleXRCamera() override;
|
virtual void HandleXRCamera(float DeltaTime) override;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, ReplicatedUsing = OnRep_ReplicatedCameraTransform, Category = "ReplicatedCamera|Networking")
|
UPROPERTY(EditDefaultsOnly, ReplicatedUsing = OnRep_ReplicatedCameraTransform, Category = "ReplicatedCamera|Networking")
|
||||||
FBPVRComponentPosRep ReplicatedCameraTransform;
|
FBPVRComponentPosRep ReplicatedCameraTransform;
|
||||||
|
|
|
@ -50,67 +50,7 @@ public:
|
||||||
UPROPERTY(Transient)
|
UPROPERTY(Transient)
|
||||||
TObjectPtr<AActor> Owner;
|
TObjectPtr<AActor> Owner;
|
||||||
|
|
||||||
bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
|
bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess);
|
||||||
{
|
|
||||||
FRepMovement BaseSettings = Owner ? Owner->GetReplicatedMovement() : FRepMovement();
|
|
||||||
|
|
||||||
// pack bitfield with flags
|
|
||||||
uint8 Flags = (bSimulatedPhysicSleep << 0) | (bRepPhysics << 1) | (bJustTeleported << 2) | (bJustTeleportedGrips << 3) | (bPausedTracking << 4);
|
|
||||||
Ar.SerializeBits(&Flags, 5);
|
|
||||||
bSimulatedPhysicSleep = (Flags & (1 << 0)) ? 1 : 0;
|
|
||||||
bRepPhysics = (Flags & (1 << 1)) ? 1 : 0;
|
|
||||||
bJustTeleported = (Flags & (1 << 2)) ? 1 : 0;
|
|
||||||
bJustTeleportedGrips = (Flags & (1 << 3)) ? 1 : 0;
|
|
||||||
bPausedTracking = (Flags & (1 << 4)) ? 1 : 0;
|
|
||||||
|
|
||||||
bOutSuccess = true;
|
|
||||||
|
|
||||||
if (bPausedTracking)
|
|
||||||
{
|
|
||||||
bOutSuccess &= PausedTrackingLoc.NetSerialize(Ar, Map, bOutSuccess);
|
|
||||||
|
|
||||||
uint16 Yaw = 0;
|
|
||||||
if (Ar.IsSaving())
|
|
||||||
{
|
|
||||||
Yaw = FRotator::CompressAxisToShort(PausedTrackingRot);
|
|
||||||
Ar << Yaw;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Ar << Yaw;
|
|
||||||
PausedTrackingRot = Yaw;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// update location, rotation, linear velocity
|
|
||||||
bOutSuccess &= SerializeQuantizedVector(Ar, Location, BaseSettings.LocationQuantizationLevel);
|
|
||||||
|
|
||||||
switch (BaseSettings.RotationQuantizationLevel)
|
|
||||||
{
|
|
||||||
case ERotatorQuantization::ByteComponents:
|
|
||||||
{
|
|
||||||
Rotation.SerializeCompressed(Ar);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ERotatorQuantization::ShortComponents:
|
|
||||||
{
|
|
||||||
Rotation.SerializeCompressedShort(Ar);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bOutSuccess &= SerializeQuantizedVector(Ar, LinearVelocity, BaseSettings.VelocityQuantizationLevel);
|
|
||||||
|
|
||||||
// update angular velocity if required
|
|
||||||
if (bRepPhysics)
|
|
||||||
{
|
|
||||||
bOutSuccess &= SerializeQuantizedVector(Ar, AngularVelocity, BaseSettings.VelocityQuantizationLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
@ -276,7 +216,7 @@ public:
|
||||||
|
|
||||||
/** BaseVR Character movement component belongs to */
|
/** BaseVR Character movement component belongs to */
|
||||||
UPROPERTY(Transient, DuplicateTransient)
|
UPROPERTY(Transient, DuplicateTransient)
|
||||||
AVRPlayerController* OwningVRPlayerController;
|
TObjectPtr<AVRPlayerController> OwningVRPlayerController;
|
||||||
|
|
||||||
// If true then we will retain roomscale tracking in relative space of the character.
|
// If true then we will retain roomscale tracking in relative space of the character.
|
||||||
// If false than the movement component will offset to the hmd tracking and the tracking will be nulled out
|
// If false than the movement component will offset to the hmd tracking and the tracking will be nulled out
|
||||||
|
|
|
@ -54,6 +54,7 @@ public:
|
||||||
static const float CLIMB_SWEEP_EDGE_REJECT_DISTANCE;
|
static const float CLIMB_SWEEP_EDGE_REJECT_DISTANCE;
|
||||||
virtual bool IsWithinClimbingEdgeTolerance(const FVector& CapsuleLocation, const FVector& TestImpactPoint, const float CapsuleRadius) const;
|
virtual bool IsWithinClimbingEdgeTolerance(const FVector& CapsuleLocation, const FVector& TestImpactPoint, const float CapsuleRadius) const;
|
||||||
virtual bool VRClimbStepUp(const FVector& GravDir, const FVector& Delta, const FHitResult &InHit, FStepDownResult* OutStepDownResult = nullptr) override;
|
virtual bool VRClimbStepUp(const FVector& GravDir, const FVector& Delta, const FHitResult &InHit, FStepDownResult* OutStepDownResult = nullptr) override;
|
||||||
|
virtual FVector GetActorFeetLocation() const override;
|
||||||
|
|
||||||
virtual bool IsWithinEdgeTolerance(const FVector& CapsuleLocation, const FVector& TestImpactPoint, const float CapsuleRadius) const override;
|
virtual bool IsWithinEdgeTolerance(const FVector& CapsuleLocation, const FVector& TestImpactPoint, const float CapsuleRadius) const override;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "Navigation/PathFollowingComponent.h"
|
#include "Navigation/PathFollowingComponent.h"
|
||||||
#include "AbstractNavData.h"
|
#include "AbstractNavData.h"
|
||||||
#include "Runtime/Launch/Resources/Version.h"
|
#include "Runtime/Launch/Resources/Version.h"
|
||||||
|
|
||||||
#include "VRPathFollowingComponent.generated.h"
|
#include "VRPathFollowingComponent.generated.h"
|
||||||
|
|
||||||
DECLARE_LOG_CATEGORY_EXTERN(LogPathFollowingVR, Warning, All);
|
DECLARE_LOG_CATEGORY_EXTERN(LogPathFollowingVR, Warning, All);
|
||||||
|
@ -18,8 +19,17 @@ class VREXPANSIONPLUGIN_API UVRPathFollowingComponent : public UPathFollowingCom
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UPROPERTY(transient)
|
|
||||||
UVRBaseCharacterMovementComponent* VRMovementComp;
|
virtual void SetNavMovementInterface(INavMovementInterface* NavMoveInterface) override;
|
||||||
|
|
||||||
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
// Update with 5.5, they are now using the interface feet location so I don't think I need to override anything anymore.
|
||||||
|
// Keeping the class intact in case people subclassed it.
|
||||||
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
|
||||||
|
|
||||||
|
/*UPROPERTY(transient)
|
||||||
|
TObjectPtr<UVRBaseCharacterMovementComponent> VRMovementComp;
|
||||||
|
|
||||||
// Add link to VRMovementComp
|
// Add link to VRMovementComp
|
||||||
void SetMovementComponent(UNavMovementComponent* MoveComp) override;
|
void SetMovementComponent(UNavMovementComponent* MoveComp) override;
|
||||||
|
@ -28,29 +38,29 @@ public:
|
||||||
// Have to override this to call the correct HasReachCurrentTarget
|
// Have to override this to call the correct HasReachCurrentTarget
|
||||||
void UpdatePathSegment() override;
|
void UpdatePathSegment() override;
|
||||||
bool HasReachedCurrentTarget(const FVector& CurrentLocation) const;
|
bool HasReachedCurrentTarget(const FVector& CurrentLocation) const;
|
||||||
|
*/
|
||||||
// Had to override this to get the correct DebugReachTest
|
// Had to override this to get the correct DebugReachTest
|
||||||
virtual void GetDebugStringTokens(TArray<FString>& Tokens, TArray<EPathFollowingDebugTokens::Type>& Flags) const override;
|
virtual void GetDebugStringTokens(TArray<FString>& Tokens, TArray<EPathFollowingDebugTokens::Type>& Flags) const override;
|
||||||
void DebugReachTest(float& CurrentDot, float& CurrentDistance, float& CurrentHeight, uint8& bDotFailed, uint8& bDistanceFailed, uint8& bHeightFailed) const;
|
/*void DebugReachTest(float& CurrentDot, float& CurrentDistance, float& CurrentHeight, uint8& bDotFailed, uint8& bDistanceFailed, uint8& bHeightFailed) const;
|
||||||
|
|
||||||
void FollowPathSegment(float DeltaTime) override;
|
void FollowPathSegment(float DeltaTime) override;
|
||||||
int32 DetermineStartingPathPoint(const FNavigationPath* ConsideredPath) const override;
|
int32 DetermineStartingPathPoint(const FNavigationPath* ConsideredPath) const override;
|
||||||
|
|
||||||
|
|
||||||
// This has a foot location when using meta paths, i'm not overriding it yet but this means that meta paths might have slightly bugged implementation.
|
// This has a foot location when using meta paths, i'm not overriding it yet but this means that meta paths might have slightly bugged implementation.
|
||||||
/** notify about finished movement */
|
// notify about finished movement
|
||||||
//virtual void OnPathFinished(const FPathFollowingResult& Result) override;
|
virtual void OnPathFinished(const FPathFollowingResult& Result) override;
|
||||||
|
*/
|
||||||
/** pause path following
|
/* pause path following
|
||||||
* @param RequestID - request to pause, FAIRequestID::CurrentRequest means pause current request, regardless of its ID */
|
* @param RequestID - request to pause, FAIRequestID::CurrentRequest means pause current request, regardless of its ID */
|
||||||
void PauseMove(FAIRequestID RequestID = FAIRequestID::CurrentRequest, EPathFollowingVelocityMode VelocityMode = EPathFollowingVelocityMode::Reset) override;
|
//void PauseMove(FAIRequestID RequestID = FAIRequestID::CurrentRequest, EPathFollowingVelocityMode VelocityMode = EPathFollowingVelocityMode::Reset) override;
|
||||||
// Now has an actor feet call .......Just a debug reference
|
// Now has an actor feet call .......Just a debug reference
|
||||||
//virtual FAIRequestID RequestMove(FNavPathSharedPtr Path, FRequestCompletedSignature OnComplete, const AActor* DestinationActor = NULL, float AcceptanceRadius = UPathFollowingComponent::DefaultAcceptanceRadius, bool bStopOnOverlap = true, FCustomMoveSharedPtr GameData = NULL) override;
|
/*virtual FAIRequestID RequestMove(FNavPathSharedPtr Path, FRequestCompletedSignature OnComplete, const AActor* DestinationActor = NULL, float AcceptanceRadius = UPathFollowingComponent::DefaultAcceptanceRadius, bool bStopOnOverlap = true, FCustomMoveSharedPtr GameData = NULL) override;
|
||||||
//
|
//
|
||||||
// Fine in 4.13
|
// Fine in 4.13
|
||||||
bool ShouldCheckPathOnResume() const override;
|
bool ShouldCheckPathOnResume() const override;
|
||||||
|
|
||||||
// Fine in 4.13, had to change feet based for both
|
// Fine in 4.13, had to change feet based for both
|
||||||
bool UpdateBlockDetection() override;
|
bool UpdateBlockDetection() override;*/
|
||||||
|
|
||||||
};
|
};
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"FileVersion": 3,
|
"FileVersion": 3,
|
||||||
"EngineAssociation": "5.4",
|
"EngineAssociation": "5.5",
|
||||||
"Category": "",
|
"Category": "",
|
||||||
"Description": "",
|
"Description": "",
|
||||||
"Modules": [
|
"Modules": [
|
||||||
|
|
Loading…
Reference in a new issue