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",
|
||||
"components": [
|
||||
"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.Tools.x86.x64",
|
||||
"Microsoft.VisualStudio.Component.Windows10SDK.22621",
|
||||
"Microsoft.VisualStudio.Component.Windows11SDK.22621",
|
||||
"Microsoft.VisualStudio.Workload.CoreEditor",
|
||||
"Microsoft.VisualStudio.Workload.ManagedDesktop",
|
||||
"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,
|
||||
"Version": 5.4,
|
||||
"VersionName": "5.4",
|
||||
"Version": 5.5,
|
||||
"VersionName": "5.5",
|
||||
"FriendlyName": "OpenXRExpansionPlugin",
|
||||
"Description": "An set of utility functions for OpenXR",
|
||||
"Category": "Virtual Reality",
|
||||
|
@ -39,10 +39,10 @@
|
|||
"Name": "OpenXR",
|
||||
"Enabled": true,
|
||||
"PlatformAllowList": [
|
||||
"Win64",
|
||||
"Linux",
|
||||
"Android"
|
||||
]
|
||||
"Win64",
|
||||
"Linux",
|
||||
"Android"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "XRBase",
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "CoreMinimal.h"
|
||||
#include "UObject/ObjectMacros.h"
|
||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||
#include "Animation/BoneReference.h"
|
||||
#include "UObject/Object.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
|
||||
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();
|
||||
return MyOwner->HasLocalNetOwner();
|
||||
#else
|
||||
//#else
|
||||
// I like epics new authority check more than mine
|
||||
const AActor* MyOwner = GetOwner();
|
||||
/* const AActor* MyOwner = GetOwner();
|
||||
const APawn* MyPawn = Cast<APawn>(MyOwner);
|
||||
|
||||
return MyPawn ? MyPawn->IsLocallyControlled() : (MyOwner && MyOwner->GetLocalRole() == ENetRole::ROLE_Authority);
|
||||
#endif
|
||||
return MyPawn ? MyPawn->IsLocallyControlled() : (MyOwner && MyOwner->GetLocalRole() == ENetRole::ROLE_Authority);*/
|
||||
//#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
|
||||
|
|
|
@ -7214,10 +7214,10 @@ void UGripMotionControllerComponent::ApplyTrackingParameters(FVector& OriginalPo
|
|||
if (GEngine->XRSystem->GetCurrentPose(IXRTrackingSystem::HMDDeviceId, curRot, curLoc))
|
||||
{
|
||||
|
||||
if (IsValid(AttachChar) && AttachChar->VRReplicatedCamera)
|
||||
/*if (IsValid(AttachChar) && AttachChar->VRReplicatedCamera)
|
||||
{
|
||||
AttachChar->VRReplicatedCamera->ApplyTrackingParameters(curLoc, true);
|
||||
}
|
||||
}*/
|
||||
|
||||
//curLoc.Z = 0;
|
||||
LastLocationForLateUpdate = curLoc;
|
||||
|
@ -7234,7 +7234,7 @@ void UGripMotionControllerComponent::ApplyTrackingParameters(FVector& OriginalPo
|
|||
if (IsValid(AttachChar) && AttachChar->VRReplicatedCamera)
|
||||
{
|
||||
// Sample camera location instead
|
||||
LastLocationForLateUpdate = AttachChar->VRReplicatedCamera->GetRelativeLocation();
|
||||
LastLocationForLateUpdate = AttachChar->VRReplicatedCamera->ReplicatedCameraTransform.Position; //GetRelativeLocation();
|
||||
|
||||
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
|
||||
// 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
|
||||
|
@ -152,13 +152,23 @@ void AGrippableActor::GatherCurrentMovement()
|
|||
bool bFoundInCache = false;
|
||||
|
||||
UWorld* World = GetWorld();
|
||||
|
||||
const bool bShouldUsePhysicsReplicationCache = GetPhysicsReplicationMode() != EPhysicsReplicationMode::Default;
|
||||
int ServerFrame = 0;
|
||||
if (FPhysScene_Chaos* Scene = static_cast<FPhysScene_Chaos*>(World->GetPhysicsScene()))
|
||||
|
||||
if (bShouldUsePhysicsReplicationCache)
|
||||
{
|
||||
if (const FRigidBodyState* FoundState = Scene->GetStateFromReplicationCache(RootPrimComp, ServerFrame))
|
||||
if (FPhysScene_Chaos* Scene = static_cast<FPhysScene_Chaos*>(World->GetPhysicsScene()))
|
||||
{
|
||||
RepMovement.FillFrom(*FoundState, this, Scene->ReplicationCache.ServerFrame);
|
||||
bFoundInCache = true;
|
||||
if (const FRigidBodyState* FoundState = Scene->GetStateFromReplicationCache(RootPrimComp, /*OUT*/ServerFrame))
|
||||
{
|
||||
if (RepMovement.ServerFrame != ServerFrame)
|
||||
{
|
||||
RepMovement.FillFrom(*FoundState, this, ServerFrame);
|
||||
bWasRepMovementModified = true;
|
||||
}
|
||||
bFoundInCache = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,9 +52,16 @@ namespace PhysicsReplicationCVars
|
|||
|
||||
int32 EnableDefaultReplication = 0;
|
||||
|
||||
namespace DefaultReplicationCVars
|
||||
{
|
||||
bool bHardsnapLegacyInPT = false;
|
||||
bool bCorrectConnectedBodies = false;
|
||||
bool bCorrectConnectedBodiesFriction = true;
|
||||
}
|
||||
|
||||
namespace ResimulationCVars
|
||||
{
|
||||
bool bRuntimeCorrectionEnabled = true;
|
||||
bool bRuntimeCorrectionEnabled = false;
|
||||
bool bRuntimeVelocityCorrection = false;
|
||||
bool bRuntimeCorrectConnectedBodies = true;
|
||||
float PosStabilityMultiplier = 0.5f;
|
||||
|
@ -62,6 +69,18 @@ namespace PhysicsReplicationCVars
|
|||
float VelStabilityMultiplier = 0.5f;
|
||||
float AngVelStabilityMultiplier = 0.5f;
|
||||
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
|
||||
|
@ -92,15 +111,24 @@ namespace PhysicsReplicationCVars
|
|||
bool bSkipVelocityRepOnPosEarlyOut = true;
|
||||
bool bPostResimWaitForUpdate = false;
|
||||
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 bAlwaysHardSnap = false;
|
||||
bool bSkipReplication = false;
|
||||
bool bDontClearTarget = false;
|
||||
bool bDrawDebugTargets = false;
|
||||
bool bDrawDebugVectors = false;
|
||||
float DrawDebugZOffset = 50.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;
|
||||
|
||||
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
|
||||
FRigidBodyState CurrentState;
|
||||
|
@ -606,7 +652,42 @@ bool FPhysicsReplicationVR::ApplyRigidBodyState(float DeltaSeconds, FBodyInstanc
|
|||
// Too much error so just snap state here and be done with it
|
||||
PhysicsTarget.AccumulatedErrorSeconds = 0.0f;
|
||||
bRestoredState = true;
|
||||
BI->SetBodyTransform(IdealWorldTM, ETeleportType::ResetPhysics, bAutoWake);
|
||||
// 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);
|
||||
|
||||
// Set the new velocities
|
||||
BI->SetLinearVelocity(NewState.LinVel, false, bAutoWake);
|
||||
BI->SetAngularVelocityInRadians(FMath::DegreesToRadians(NewState.AngVel), false, bAutoWake);
|
||||
}
|
||||
|
||||
// Set the new velocities
|
||||
BI->SetLinearVelocity(NewState.LinVel, false, bAutoWake);
|
||||
|
@ -714,7 +795,8 @@ void FPhysicsReplicationVR::OnTick(float DeltaSeconds, TMap<TWeakObjectPtr<UPrim
|
|||
|
||||
|
||||
int32 LocalFrameOffset = 0; // LocalFrame = ServerFrame + LocalFrameOffset;
|
||||
if (FPhysicsSolverBase::IsNetworkPhysicsPredictionEnabled())
|
||||
bool LocalFrameOffsetAssigned = false;
|
||||
if (UPhysicsSettings::Get()->PhysicsPrediction.bEnablePhysicsPrediction)
|
||||
{
|
||||
if (UWorld* World = GetOwningWorld())
|
||||
{
|
||||
|
@ -722,6 +804,7 @@ void FPhysicsReplicationVR::OnTick(float DeltaSeconds, TMap<TWeakObjectPtr<UPrim
|
|||
{
|
||||
if (APlayerController* PlayerController = World->GetFirstPlayerController())
|
||||
{
|
||||
LocalFrameOffsetAssigned = PlayerController->GetNetworkPhysicsTickOffsetAssigned();
|
||||
LocalFrameOffset = PlayerController->GetNetworkPhysicsTickOffset();
|
||||
}
|
||||
}
|
||||
|
@ -753,6 +836,9 @@ void FPhysicsReplicationVR::OnTick(float DeltaSeconds, TMap<TWeakObjectPtr<UPrim
|
|||
{
|
||||
// Removed as this is server sided
|
||||
/*
|
||||
// Update actor replication settings overrides
|
||||
SettingsCurrent = UNetworkPhysicsSettingsComponent::GetSettingsForActor(OwningActor);
|
||||
|
||||
const ENetRole OwnerRole = OwningActor->GetLocalRole();
|
||||
const bool bIsSimulated = OwnerRole == ROLE_SimulatedProxy;
|
||||
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.ServerFrame = PhysicsTarget.ServerFrame;
|
||||
AsyncInputData.FrameOffset = LocalFrameOffset;
|
||||
|
||||
AsyncInputData.LatencyOneWay = PingSecondsOneWay;
|
||||
|
||||
if (LocalFrameOffsetAssigned)
|
||||
{
|
||||
AsyncInputData.FrameOffset = LocalFrameOffset;
|
||||
}
|
||||
|
||||
AsyncInputVR->InputData.Add(AsyncInputData);
|
||||
}
|
||||
ReplicatedTargetsQueueVR.Reset();
|
||||
|
@ -919,7 +1010,9 @@ bool FRepMovementVR::GatherActorsMovement(AActor* OwningActor)
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -990,18 +1083,18 @@ void FPhysicsReplicationAsyncVR::OnPreSimulate_Internal()
|
|||
{
|
||||
if (Input.TargetState.Flags == ERigidBodyFlags::None)
|
||||
{
|
||||
// Remove replication target
|
||||
ObjectToTarget.Remove(Input.PhysicsObject);
|
||||
// Remove replication target
|
||||
RemoveObjectFromReplication(Input.PhysicsObject);
|
||||
continue;
|
||||
}
|
||||
|
||||
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.
|
||||
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)
|
||||
{
|
||||
if (Input.PhysicsObject == nullptr)
|
||||
|
@ -1025,6 +1153,12 @@ void FPhysicsReplicationAsyncVR::UpdateRewindDataTarget(const FPhysicsRepAsyncIn
|
|||
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());
|
||||
if (RigidsSolver == nullptr)
|
||||
{
|
||||
|
@ -1041,10 +1175,10 @@ void FPhysicsReplicationAsyncVR::UpdateRewindDataTarget(const FPhysicsRepAsyncIn
|
|||
if (Chaos::FGeometryParticleHandle* Handle = Interface.GetParticle(Input.PhysicsObject))
|
||||
{
|
||||
// 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,
|
||||
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)
|
||||
{
|
||||
// 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->PrevPosTarget = Input.TargetState.Position;
|
||||
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
|
||||
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
|
||||
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->TargetState = Input.TargetState;
|
||||
Target->RepMode = Input.RepMode;
|
||||
Target->FrameOffset = Input.FrameOffset;
|
||||
Target->FrameOffset = Input.FrameOffset.IsSet() ? *Input.FrameOffset : 0;
|
||||
Target->TickCount = 0;
|
||||
Target->AccumulatedSleepSeconds = 0.0f;
|
||||
|
||||
|
@ -1145,6 +1282,8 @@ void FPhysicsReplicationAsyncVR::UpdateAsyncTarget(const FPhysicsRepAsyncInputDa
|
|||
if (CVarDrawDebugTargets->GetBool())
|
||||
{
|
||||
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"));
|
||||
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
|
||||
if (!bFirstTarget && bPrevAllowTargetAltering && Target->bAllowTargetAltering)
|
||||
if (!bFirstTarget && bPrevAllowTargetAltering && Target->bAllowTargetAltering && !bFrameOffsetCorrected)
|
||||
{
|
||||
static const auto CVarTargetTickAlignmentClampMultiplier = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.TargetTickAlignmentClampMultiplier"));
|
||||
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)
|
||||
{
|
||||
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();
|
||||
if (FGeometryParticleHandle* Handle = Interface.GetParticle(POHandle))
|
||||
|
@ -1266,6 +1406,8 @@ void FPhysicsReplicationAsyncVR::ApplyTargetStatesAsync(const float DeltaSeconds
|
|||
|
||||
if (FPBDRigidParticleHandle* RigidHandle = Handle->CastToRigidParticle())
|
||||
{
|
||||
ParticleID = RigidHandle->ParticleID();
|
||||
|
||||
// Cache custom settings for this object if there are any
|
||||
FetchObjectSettings(POHandle);
|
||||
|
||||
|
@ -1290,6 +1432,7 @@ void FPhysicsReplicationAsyncVR::ApplyTargetStatesAsync(const float DeltaSeconds
|
|||
|
||||
if (bRemoveItr)
|
||||
{
|
||||
ReplicatedParticleIDs.Remove(ParticleID);
|
||||
Itr.RemoveCurrent();
|
||||
}
|
||||
}
|
||||
|
@ -1463,7 +1606,8 @@ bool FPhysicsReplicationAsyncVR::DefaultReplication(Chaos::FPBDRigidParticleHand
|
|||
const float AngularVelocityCoefficient = CVarAngLerp->GetFloat() >= 0.0f ? CVarAngLerp->GetFloat() : ErrorCorrectionDefault.AngularVelocityCoefficient;
|
||||
|
||||
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
|
||||
FRigidBodyState CurrentState;
|
||||
|
@ -1582,8 +1726,11 @@ bool FPhysicsReplicationAsyncVR::DefaultReplication(Chaos::FPBDRigidParticleHand
|
|||
// Too much error so just snap state here and be done with it
|
||||
Target.AccumulatedErrorSeconds = 0.0f;
|
||||
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->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"));
|
||||
if (CVarDrawDebugTargets->GetBool())
|
||||
{
|
||||
// Needs updated post 5.5 for DrawDebugZ CVAR
|
||||
|
||||
const FVector Offset = FVector(0.0f, 0.0f, 50.0f);
|
||||
const FVector StartPos = Target.TargetState.Position + Offset;
|
||||
const int32 SizeMultiplier = FMath::Clamp(Target.TickCount, -4, 30);
|
||||
|
@ -1675,15 +1824,21 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
|||
if (bOkToClear && bShouldSleep && bCanSimulate)
|
||||
{
|
||||
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 CVarDontClearTarget = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.DontClearTarget"));
|
||||
// --- Should replication stop? ---
|
||||
const bool bClearTarget =
|
||||
(!bCanSimulate
|
||||
|| (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))
|
||||
((bOkToClear && bShouldSleep && Target.AccumulatedSleepSeconds >= CVarSleepSecondsClearTarget->GetFloat()) // Allow clearing the target due to sleeping after the object has been 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 && !bCanSimulate)) // If replication say it's okay to clear the target and the object can't simulate, clear the target
|
||||
&& !CVarDontClearTarget->GetBool();
|
||||
|
||||
// --- Target Prediction ---
|
||||
|
@ -1694,10 +1849,16 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
|||
const int32 ExtrapolationTickLimit = FMath::Max(
|
||||
FMath::CeilToInt(Target.AverageReceiveInterval * CVarExtrapolationTimeMultiplier->GetFloat()), // Extrapolate time based on receive interval * multiplier
|
||||
FMath::CeilToInt(CVarExtrapolationMinTime->GetFloat() / DeltaSeconds)); // At least extrapolate for N seconds
|
||||
|
||||
if (Target.TickCount <= ExtrapolationTickLimit)
|
||||
{
|
||||
FPhysicsReplicationAsyncVR::ExtrapolateTarget(Target, 1, DeltaSeconds);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we reach the extrapolation limit, disable target from being altered
|
||||
Target.bAllowTargetAltering = false;
|
||||
}
|
||||
}
|
||||
|
||||
return bClearTarget;
|
||||
|
@ -1716,26 +1877,21 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
|||
// Get the rotational offset between the blended rotation target and the current rotation
|
||||
const FQuat TargetRotDelta = Target.TargetState.Quaternion * Handle->GetR().Inverse();
|
||||
|
||||
// Convert to angle axis
|
||||
// Convert to angle and axis
|
||||
float Angle;
|
||||
FVector Axis;
|
||||
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"));
|
||||
if (Angle < FMath::DegreesToRadians(CVarEarlyOutAngle->GetFloat()))
|
||||
if (Angle < CVarEarlyOutAngle->GetFloat())
|
||||
{
|
||||
// Early Out
|
||||
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"));
|
||||
// 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));
|
||||
|
@ -1745,13 +1901,13 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
|||
CurrentState.Position = Handle->GetX();
|
||||
CurrentState.Quaternion = Handle->GetR();
|
||||
CurrentState.LinVel = Handle->GetV();
|
||||
CurrentState.AngVel = Handle->GetW(); // Note: Current angular velocity is in Radians
|
||||
CurrentState.AngVel = Handle->GetW(); // Radians
|
||||
|
||||
// NewState
|
||||
const FVector TargetPos = FVector(Target.TargetState.Position);
|
||||
const FQuat TargetRot = Target.TargetState.Quaternion;
|
||||
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 ---
|
||||
* 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 CVarAlwaysHardSnap = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.AlwaysHardSnap"));
|
||||
const bool bHardSnap = !bCanSimulate ||
|
||||
Target.AccumulatedErrorSeconds > CVarErrorAccumulationSeconds->GetFloat() ||
|
||||
CVarAlwaysHardSnap->GetBool();
|
||||
static const auto CVarKinematicHardSnap = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.KinematicHardSnap"));
|
||||
|
||||
const bool bHardSnap = (!bCanSimulate && CVarKinematicHardSnap->GetBool())
|
||||
|| Target.AccumulatedErrorSeconds > CVarErrorAccumulationSeconds->GetFloat()
|
||||
|| CVarAlwaysHardSnap->GetBool();
|
||||
|
||||
if (bHardSnap)
|
||||
{
|
||||
|
@ -1815,13 +1973,13 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
|||
}
|
||||
else
|
||||
{
|
||||
// Set XPRQVW to hard snap dynamic object
|
||||
Handle->SetX(Target.PrevPosTarget);
|
||||
Handle->SetP(Target.PrevPosTarget);
|
||||
Handle->SetR(Target.PrevRotTarget);
|
||||
Handle->SetQ(Target.PrevRotTarget);
|
||||
Handle->SetV(Target.TargetState.LinVel);
|
||||
Handle->SetW(FMath::DegreesToRadians(Target.TargetState.AngVel));
|
||||
// Set XRVW to hard snap dynamic object and force recalculation of friction
|
||||
const bool bCorrectConnectedBodies = SettingsCurrent.PredictiveInterpolationSettings.GetCorrectConnectedBodies();
|
||||
RigidsSolver->GetEvolution()->ApplyParticleTransformCorrection(Handle, Target.PrevPosTarget, Target.PrevRotTarget, bCorrectConnectedBodies, /*bInRecalculateFrictionOnConnectedBodies*/ true, ReplicatedParticleIDs);
|
||||
|
||||
|
||||
Handle->SetV(TargetLinVel);
|
||||
Handle->SetW(TargetAngVel);
|
||||
}
|
||||
|
||||
// Cache data for next replication
|
||||
|
@ -1830,8 +1988,72 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
|||
// End replication and go to sleep if that's requested
|
||||
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
|
||||
{
|
||||
// Wake up if sleeping
|
||||
if (bIsSleeping)
|
||||
{
|
||||
RigidsSolver->GetEvolution()->SetParticleObjectState(Handle, Chaos::EObjectStateType::Dynamic);
|
||||
}
|
||||
|
||||
// Calculate interpolation time based on current average receive rate
|
||||
const float AverageReceiveIntervalSeconds = Target.AverageReceiveInterval * DeltaSeconds;
|
||||
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(),
|
||||
DeltaSeconds + SettingsCurrent.PredictiveInterpolationSettings.GetRotCorrectionTimeMin());
|
||||
|
||||
FVector CorrectionX = CurrentState.Position;
|
||||
if ((bXCanEarlyOut && SettingsCurrent.PredictiveInterpolationSettings.GetSkipVelocityRepOnPosEarlyOut()) == false)
|
||||
{ // --- Velocity Replication ---
|
||||
|
||||
|
@ -1853,10 +2076,10 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
|||
const FVector LinVelDiff = -CurrentState.LinVel + TargetLinVel;
|
||||
|
||||
// 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;
|
||||
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())
|
||||
{
|
||||
// Convert PosDiff to a velocity
|
||||
|
@ -1866,20 +2089,21 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
|||
const FVector BlendedTargetVelocity = LinVelDiff + PosDiffVelocity;
|
||||
|
||||
// Add BlendedTargetVelocity onto current velocity
|
||||
|
||||
RepLinVel = CurrentState.LinVel + (BlendedTargetVelocity * Alpha);
|
||||
RepLinVel = CurrentState.LinVel + (BlendedTargetVelocity * VelocityAlpha); // Same as (BlendedTargetVelocity / InterpolationTime) * DeltaSeconds
|
||||
}
|
||||
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
|
||||
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
|
||||
Handle->SetX(Handle->GetX() + PosDiffVelocityDelta);
|
||||
// Calculate the PosDiff amount to correct this tick
|
||||
const FVector PosDiffVelocityDelta = PosDiff * CorrectionAlpha; // Same as (PosDiff / PosCorrectionTime) * DeltaSeconds
|
||||
|
||||
// The new position after correction
|
||||
CorrectionX = Handle->GetX() + PosDiffVelocityDelta;
|
||||
}
|
||||
|
||||
// Apply velocity replication
|
||||
|
@ -1890,7 +2114,8 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
|||
static const auto CVarDrawDebugVectors = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.PredictiveInterpolation.DrawDebugVectors"));
|
||||
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 StartPos = TargetPos + Offset;
|
||||
FVector Direction = TargetLinVel;
|
||||
|
@ -1908,37 +2133,63 @@ bool FPhysicsReplicationAsyncVR::PredictiveInterpolation(Chaos::FPBDRigidParticl
|
|||
Target.PrevLinVel = FVector(RepLinVel);
|
||||
}
|
||||
|
||||
FQuat CorrectionR = CurrentState.Quaternion;
|
||||
{ // --- Angular Velocity Replication ---
|
||||
/* Todo, Implement InterpolationTime */
|
||||
|
||||
// Extrapolate current rotation along current angular velocity to see where we would end up
|
||||
float CurAngVelSize;
|
||||
FVector CurAngVelAxis;
|
||||
CurrentState.AngVel.FVector::ToDirectionAndLength(CurAngVelAxis, CurAngVelSize);
|
||||
const FQuat CurRotExtrapDelta = FQuat(CurAngVelAxis, CurAngVelSize * DeltaSeconds);
|
||||
const FQuat CurRotExtrap = CurRotExtrapDelta * CurrentState.Quaternion;
|
||||
// Get AngVelDiff by adding inverted CurrentState.AngVel to TargetAngVel
|
||||
const FVector AngVelDiff = -CurrentState.AngVel + TargetAngVel;
|
||||
|
||||
// Slerp from the extrapolated current rotation towards the target rotation
|
||||
// This takes current angular velocity into account
|
||||
const float RotCorrectionAmount = FMath::Clamp(DeltaSeconds / RotCorrectionTime, 0.0f, 1.0f);
|
||||
const FQuat TargetRotBlended = FQuat::Slerp(CurRotExtrap, TargetRot, RotCorrectionAmount);
|
||||
// Calculate velocity blend amount for this tick as an alpha value
|
||||
const float VelocityAlpha = FMath::Clamp(DeltaSeconds / InterpolationTime, 0.0f, 1.0f);
|
||||
|
||||
// Get the rotational offset between the blended rotation target and the current rotation
|
||||
const FQuat TargetRotDelta = TargetRotBlended * CurrentState.Quaternion.Inverse();
|
||||
FVector RepAngVel;
|
||||
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
|
||||
float WAngle;
|
||||
FVector WAxis;
|
||||
TargetRotDelta.ToAxisAndAngle(WAxis, WAngle);
|
||||
const FVector TargetRotDeltaBlend = FVector(WAxis * (WAngle / (DeltaSeconds * SettingsCurrent.PredictiveInterpolationSettings.GetRotInterpolationTimeMultiplier())));
|
||||
const FVector RepAngVel = FMath::DegreesToRadians(TargetAngVel) + TargetRotDeltaBlend;
|
||||
// Convert RotDiff to a velocity
|
||||
float WAngle;
|
||||
FVector WAxis;
|
||||
RotDiff.ToAxisAndAngle(WAxis, WAngle);
|
||||
WAngle = FMath::UnwindRadians(WAngle);
|
||||
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);
|
||||
}
|
||||
|
||||
// Cache data for next replication
|
||||
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)
|
||||
{
|
||||
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,
|
||||
FMath::Clamp(SettingsCurrent.PredictiveInterpolationSettings.GetSoftSnapRotStrength(), 0.0f, 1.0f));
|
||||
|
||||
Handle->SetX(SoftSnapPos);
|
||||
Handle->SetP(SoftSnapPos);
|
||||
Handle->SetR(SoftSnapRot);
|
||||
Handle->SetQ(SoftSnapRot);
|
||||
// Apply correction as a transform shift
|
||||
const bool bCorrectConnectedBodies = SettingsCurrent.PredictiveInterpolationSettings.GetCorrectConnectedBodies();
|
||||
const bool bCorrectConnectedBodiesFriction = SettingsCurrent.PredictiveInterpolationSettings.GetCorrectConnectedBodiesFriction();
|
||||
RigidsSolver->GetEvolution()->ApplyParticleTransformCorrection(Handle, SoftSnapPos, SoftSnapRot, bCorrectConnectedBodies, bCorrectConnectedBodiesFriction, ReplicatedParticleIDs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2003,17 +2254,48 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
|
|||
return true;
|
||||
}
|
||||
|
||||
const bool bShouldSleep = (Target.TargetState.Flags & ERigidBodyFlags::Sleeping) != 0;
|
||||
bool bClearTarget = true;
|
||||
|
||||
|
||||
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 FVector ErrorOffset = (Target.TargetState.Position - PastState.GetX());
|
||||
const float ErrorDistance = ErrorOffset.Size();
|
||||
const bool ShouldTriggerResim = ErrorDistance >= ResimErrorThreshold;
|
||||
// Check which comparisons to perform to trigger resimulation from
|
||||
const bool bCompareX = Chaos::FPhysicsSolverBase::GetResimulationErrorPositionThresholdEnabled() || SettingsCurrent.ResimulationSettings.bOverrideResimulationErrorPositionThreshold;
|
||||
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)
|
||||
|
@ -2021,7 +2303,7 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
|
|||
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("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 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());
|
||||
|
@ -2032,7 +2314,7 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
|
|||
if (CVarResimDrawDebug->GetBool())
|
||||
{
|
||||
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);
|
||||
|
||||
static const auto CVarNetCorrectionLifetime = IConsoleManager::Get().FindConsoleVariable(TEXT("p.NetCorrectionLifetime"));
|
||||
|
@ -2042,57 +2324,58 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
|
|||
}
|
||||
#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
|
||||
RigidsSolver->GetEvolution()->GetIslandManager().SetParticleResimFrame(Handle, LocalFrame);
|
||||
|
||||
int32 ResimFrame = RewindData->GetResimFrame();
|
||||
ResimFrame = (ResimFrame == INDEX_NONE) ? LocalFrame : FMath::Min(ResimFrame, LocalFrame);
|
||||
RewindData->SetResimFrame(ResimFrame);
|
||||
}
|
||||
else if (SettingsCurrent.ResimulationSettings.GetRuntimeCorrectionEnabled())
|
||||
{
|
||||
const int32 NumPredictedFrames = RigidsSolver->GetCurrentFrame() - LocalFrame - Target.TickCount;
|
||||
|
||||
if (Target.TickCount <= NumPredictedFrames && NumPredictedFrames > 0)
|
||||
{
|
||||
// Trigger resimulation
|
||||
RigidsSolver->GetEvolution()->GetIslandManager().SetParticleResimFrame(Handle, LocalFrame);
|
||||
const FVector ErrorOffset = (Target.TargetState.Position - PastState.GetX());
|
||||
|
||||
int32 ResimFrame = RewindData->GetResimFrame();
|
||||
ResimFrame = (ResimFrame == INDEX_NONE) ? LocalFrame : FMath::Min(ResimFrame, LocalFrame);
|
||||
RewindData->SetResimFrame(ResimFrame);
|
||||
}
|
||||
else if (SettingsCurrent.ResimulationSettings.GetRuntimeCorrectionEnabled())
|
||||
// Positional Correction
|
||||
const float CorrectionAmountX = SettingsCurrent.ResimulationSettings.GetPosStabilityMultiplier() / NumPredictedFrames;
|
||||
const FVector PosDiffCorrection = ErrorOffset * CorrectionAmountX; // Same result as (ErrorOffset / NumPredictedFrames) * PosStabilityMultiplier
|
||||
const FVector CorrectedX = Handle->GetX() + PosDiffCorrection;
|
||||
|
||||
{
|
||||
const int32 NumPredictedFrames = RigidsSolver->GetCurrentFrame() - LocalFrame - Target.TickCount;
|
||||
// Rotational Correction
|
||||
const float CorrectionAmountR = SettingsCurrent.ResimulationSettings.GetRotStabilityMultiplier() / NumPredictedFrames;
|
||||
const FQuat DeltaQuat = PastState.GetR().Inverse() * Target.TargetState.Quaternion;
|
||||
const FQuat TargetCorrectionR = Handle->GetR() * DeltaQuat;
|
||||
const FQuat CorrectedR = FQuat::Slerp(Handle->GetR(), TargetCorrectionR, CorrectionAmountR);
|
||||
|
||||
|
||||
|
||||
if (Target.TickCount <= NumPredictedFrames && NumPredictedFrames > 0)
|
||||
if (SettingsCurrent.ResimulationSettings.GetRuntimeVelocityCorrectionEnabled())
|
||||
{
|
||||
// Positional Correction
|
||||
const float CorrectionAmountX = SettingsCurrent.ResimulationSettings.GetPosStabilityMultiplier() / NumPredictedFrames;
|
||||
const FVector PosDiffCorrection = ErrorOffset * CorrectionAmountX; // Same result as (ErrorOffset / NumPredictedFrames) * PosStabilityMultiplier
|
||||
const FVector CorrectedX = Handle->GetX() + PosDiffCorrection;
|
||||
// Linear Velocity Correction
|
||||
const FVector LinVelDiff = Target.TargetState.LinVel - PastState.GetV(); // Velocity vector that the server covers but the client doesn't
|
||||
const float CorrectionAmountV = SettingsCurrent.ResimulationSettings.GetVelStabilityMultiplier() / NumPredictedFrames;
|
||||
const FVector VelCorrection = LinVelDiff * CorrectionAmountV; // Same result as (LinVelDiff / NumPredictedFrames) * VelStabilityMultiplier
|
||||
const FVector CorrectedV = Handle->GetV() + VelCorrection;
|
||||
|
||||
// Angular Velocity Correction
|
||||
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 FVector AngVelCorrection = AngVelDiff * CorrectionAmountW; // Same result as (AngVelDiff / NumPredictedFrames) * VelStabilityMultiplier
|
||||
const FVector CorrectedW = Handle->GetW() + AngVelCorrection;
|
||||
|
||||
// Rotational Correction
|
||||
const float CorrectionAmountR = SettingsCurrent.ResimulationSettings.GetRotStabilityMultiplier() / NumPredictedFrames;
|
||||
|
||||
const FQuat DeltaQuat = PastState.GetR().Inverse() * Target.TargetState.Quaternion;
|
||||
const FQuat TargetCorrectionR = Handle->GetR() * DeltaQuat;
|
||||
const FQuat CorrectedR = FQuat::Slerp(Handle->GetR(), TargetCorrectionR, CorrectionAmountR);
|
||||
|
||||
if (SettingsCurrent.ResimulationSettings.GetRuntimeVelocityCorrectionEnabled())
|
||||
{
|
||||
// Linear Velocity Correction
|
||||
const FVector LinVelDiff = Target.TargetState.LinVel - PastState.GetV(); // Velocity vector that the server covers but the client doesn't
|
||||
const float CorrectionAmountV = SettingsCurrent.ResimulationSettings.GetVelStabilityMultiplier() / NumPredictedFrames;
|
||||
const FVector VelCorrection = LinVelDiff * CorrectionAmountV; // Same result as (LinVelDiff / NumPredictedFrames) * VelStabilityMultiplier
|
||||
const FVector CorrectedV = Handle->GetV() + VelCorrection;
|
||||
|
||||
// Angular Velocity Correction
|
||||
const FVector AngVelDiff = 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 FVector AngVelCorrection = AngVelDiff * CorrectionAmountW; // Same result as (AngVelDiff / NumPredictedFrames) * VelStabilityMultiplier
|
||||
const FVector CorrectedW = Handle->GetW() + AngVelCorrection;
|
||||
|
||||
// Apply correction to velocities
|
||||
Handle->SetV(CorrectedV);
|
||||
Handle->SetW(CorrectedW);
|
||||
}
|
||||
// Apply correction to velocities
|
||||
Handle->SetV(CorrectedV);
|
||||
Handle->SetW(CorrectedW);
|
||||
}
|
||||
|
||||
|
||||
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
|
||||
|
@ -2103,14 +2386,27 @@ bool FPhysicsReplicationAsyncVR::ResimulationReplication(Chaos::FPBDRigidParticl
|
|||
}
|
||||
#endif
|
||||
// Apply correction to position and rotation
|
||||
static const auto CVarResimRuntimeCorrectConnectedBodies = IConsoleManager::Get().FindConsoleVariable(TEXT("np2.Resim.RuntimeCorrectConnectedBodies"));
|
||||
RigidsSolver->GetEvolution()->ApplyParticleTransformCorrection(Handle, CorrectedX, CorrectedR, CVarResimRuntimeCorrectConnectedBodies->GetBool());
|
||||
}
|
||||
RigidsSolver->GetEvolution()->ApplyParticleTransformCorrection(Handle, CorrectedX, CorrectedR, SettingsCurrent.ResimulationSettings.GetRuntimeCorrectConnectedBodies(), /*bInRecalculateFrictionOnConnectedBodies*/true, ReplicatedParticleIDs);
|
||||
}
|
||||
|
||||
// Keep target for NumPredictedFrames time to perform runtime corrections with until a new target is received
|
||||
bClearTarget = Target.TickCount >= NumPredictedFrames;
|
||||
// Keep target for NumPredictedFrames time to perform runtime corrections with until a new target is received
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include "PhysicsReplication.h"
|
||||
#include "Physics/Experimental/PhysScene_Chaos.h"
|
||||
#include "PhysicsEngine/PhysicsAsset.h" // Tmp until epic bug fixes skeletal welding
|
||||
#include "PhysicsEngine/BodySetup.h"
|
||||
#include "PhysicsEngine/SkeletalBodySetup.h"
|
||||
#if WITH_PUSH_MODEL
|
||||
#include "Net/Core/PushModel/PushModel.h"
|
||||
#endif
|
||||
|
@ -63,7 +65,7 @@ void UOptionalRepSkeletalMeshComponent::GetWeldedBodies(TArray<FBodyInstance*>&
|
|||
OutWeldedBodies.Add(BI);
|
||||
if (PhysicsAsset)
|
||||
{
|
||||
if (UBodySetup* PhysicsAssetBodySetup = PhysicsAsset->SkeletalBodySetups[BodyIdx])
|
||||
if (UBodySetup* PhysicsAssetBodySetup = PhysicsAsset->SkeletalBodySetups[BodyIdx].Get())
|
||||
{
|
||||
OutLabels.Add(PhysicsAssetBodySetup->BoneName);
|
||||
}
|
||||
|
@ -156,7 +158,7 @@ AGrippableSkeletalMeshActor::AGrippableSkeletalMeshActor(const FObjectInitialize
|
|||
|
||||
// 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
|
||||
MinNetUpdateFrequency = 30.0f;
|
||||
SetMinNetUpdateFrequency(30.0f);
|
||||
}
|
||||
|
||||
void AGrippableSkeletalMeshActor::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty >& OutLifetimeProps) const
|
||||
|
@ -254,13 +256,23 @@ void AGrippableSkeletalMeshActor::GatherCurrentMovement()
|
|||
bool bFoundInCache = false;
|
||||
|
||||
UWorld* World = GetWorld();
|
||||
|
||||
const bool bShouldUsePhysicsReplicationCache = GetPhysicsReplicationMode() != EPhysicsReplicationMode::Default;
|
||||
int ServerFrame = 0;
|
||||
if (FPhysScene_Chaos* Scene = static_cast<FPhysScene_Chaos*>(World->GetPhysicsScene()))
|
||||
|
||||
if (bShouldUsePhysicsReplicationCache)
|
||||
{
|
||||
if (const FRigidBodyState* FoundState = Scene->GetStateFromReplicationCache(RootPrimComp, ServerFrame))
|
||||
if (FPhysScene_Chaos* Scene = static_cast<FPhysScene_Chaos*>(World->GetPhysicsScene()))
|
||||
{
|
||||
RepMovement.FillFrom(*FoundState, this, Scene->ReplicationCache.ServerFrame);
|
||||
bFoundInCache = true;
|
||||
if (const FRigidBodyState* FoundState = Scene->GetStateFromReplicationCache(RootPrimComp, /*OUT*/ServerFrame))
|
||||
{
|
||||
if (RepMovement.ServerFrame != ServerFrame)
|
||||
{
|
||||
RepMovement.FillFrom(*FoundState, this, ServerFrame);
|
||||
bWasRepMovementModified = true;
|
||||
}
|
||||
bFoundInCache = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "VRExpansionFunctionLibrary.h"
|
||||
#include "GripScripts/VRGripScriptBase.h"
|
||||
#include "PhysicsEngine/PhysicsAsset.h" // Tmp until epic bug fixes skeletal welding
|
||||
#include "PhysicsEngine/SkeletalBodySetup.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
#if WITH_PUSH_MODEL
|
||||
#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
|
||||
// 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
|
||||
|
@ -203,13 +203,23 @@ void AGrippableStaticMeshActor::GatherCurrentMovement()
|
|||
bool bFoundInCache = false;
|
||||
|
||||
UWorld* World = GetWorld();
|
||||
|
||||
const bool bShouldUsePhysicsReplicationCache = GetPhysicsReplicationMode() != EPhysicsReplicationMode::Default;
|
||||
int ServerFrame = 0;
|
||||
if (FPhysScene_Chaos* Scene = static_cast<FPhysScene_Chaos*>(World->GetPhysicsScene()))
|
||||
|
||||
if (bShouldUsePhysicsReplicationCache)
|
||||
{
|
||||
if (const FRigidBodyState* FoundState = Scene->GetStateFromReplicationCache(RootPrimComp, ServerFrame))
|
||||
if (FPhysScene_Chaos* Scene = static_cast<FPhysScene_Chaos*>(World->GetPhysicsScene()))
|
||||
{
|
||||
RepMovement.FillFrom(*FoundState, this, Scene->ReplicationCache.ServerFrame);
|
||||
bFoundInCache = true;
|
||||
if (const FRigidBodyState* FoundState = Scene->GetStateFromReplicationCache(RootPrimComp, /*OUT*/ServerFrame))
|
||||
{
|
||||
if (RepMovement.ServerFrame != ServerFrame)
|
||||
{
|
||||
RepMovement.FillFrom(*FoundState, this, ServerFrame);
|
||||
bWasRepMovementModified = true;
|
||||
}
|
||||
bFoundInCache = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,20 +253,20 @@ void AGrippableStaticMeshActor::GatherCurrentMovement()
|
|||
|
||||
// Technically, the values might have stayed the same, but we'll just assume they've changed.
|
||||
bWasAttachmentModified = true;
|
||||
|
||||
#if UE_WITH_IRIS
|
||||
// If RepPhysics has changed value then notify the ReplicationSystem
|
||||
if (bPrevRepPhysics != GetReplicatedMovement_Mutable().bRepPhysics)
|
||||
{
|
||||
UpdateReplicatePhysicsCondition();
|
||||
}
|
||||
#endif // UE_WITH_IRIS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Technically, the values might have stayed the same, but we'll just assume they've changed.
|
||||
bWasRepMovementModified = true;
|
||||
|
||||
#if UE_WITH_IRIS
|
||||
// If RepPhysics has changed value then notify the ReplicationSystem
|
||||
if (bPrevRepPhysics != GetReplicatedMovement_Mutable().bRepPhysics)
|
||||
{
|
||||
UpdateReplicatePhysicsCondition();
|
||||
}
|
||||
#endif // UE_WITH_IRIS
|
||||
}
|
||||
else if (RootComponent != nullptr)
|
||||
{
|
||||
|
|
|
@ -272,7 +272,7 @@ void UVRDialComponent::OnGripRelease_Implementation(UGripMotionControllerCompone
|
|||
float AngleOffsetCheck = FMath::Abs(FRotator::ClampAxis(CurRotBackEnd) - FRotator::ClampAxis(LastSnapAngle));
|
||||
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))
|
||||
{
|
||||
|
@ -592,7 +592,7 @@ void UVRDialComponent::AddDialAngle(float DialAngleDelta, bool bCallEvents, bool
|
|||
float AngleOffsetCheck = FMath::Abs(FRotator::ClampAxis(CurRotBackEnd) - FRotator::ClampAxis(LastSnapAngle));
|
||||
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))
|
||||
{
|
||||
|
|
|
@ -810,7 +810,7 @@ FVector UVRSliderComponent::GetPerAxisSliderProgress()
|
|||
CalculatedLocation = bSlideDistanceIsInParentSpace ? CalculatedLocation * InitialRelativeTransform.GetScale3D() : CalculatedLocation;
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
//#include "Chaos/ParticleHandle.h"
|
||||
#include "PhysicsEngine/PhysicsAsset.h"
|
||||
#include "PhysicsEngine/PhysicsAsset.h"
|
||||
#include "PhysicsEngine/SkeletalBodySetup.h"
|
||||
#include "Physics/Experimental/PhysScene_Chaos.h"
|
||||
#include "Chaos/KinematicGeometryParticles.h"
|
||||
#include "PhysicsProxy/SingleParticlePhysicsProxy.h"
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "Net/UnrealNetwork.h"
|
||||
#include "PhysicsReplication.h"
|
||||
#include "PhysicsEngine/PhysicsAsset.h"
|
||||
#include "PhysicsEngine/BodySetup.h"
|
||||
#include "PhysicsEngine/SkeletalBodySetup.h"
|
||||
#if WITH_PUSH_MODEL
|
||||
#include "Net/Core/PushModel/PushModel.h"
|
||||
#endif
|
||||
|
@ -269,7 +271,7 @@ void UInversePhysicsSkeletalMeshComponent::GetWeldedBodies(TArray<FBodyInstance*
|
|||
OutWeldedBodies.Add(BI);
|
||||
if (PhysicsAsset)
|
||||
{
|
||||
if (UBodySetup* PhysicsAssetBodySetup = PhysicsAsset->SkeletalBodySetups[BodyIdx])
|
||||
if (UBodySetup* PhysicsAssetBodySetup = PhysicsAsset->SkeletalBodySetups[BodyIdx].Get())
|
||||
{
|
||||
OutLabels.Add(PhysicsAssetBodySetup->BoneName);
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ FORCEINLINE_DEBUGGABLE bool CheckIsTargetInSightPie(const FPerceptionListener& L
|
|||
const FAISightTargetVR::FTargetId FAISightTargetVR::InvalidTargetId = FAISystem::InvalidUnsignedID;
|
||||
|
||||
FAISightTargetVR::FAISightTargetVR(AActor* InTarget, FGenericTeamId InTeamId)
|
||||
: Target(InTarget), SightTargetInterface(nullptr), TeamId(InTeamId)
|
||||
: Target(InTarget), TeamId(InTeamId)
|
||||
{
|
||||
if (InTarget)
|
||||
{
|
||||
|
@ -587,7 +587,7 @@ UAISense_Sight::EVisibilityResult UAISense_Sight_VR::ComputeVisibility(UWorld* W
|
|||
return UAISense_Sight::EVisibilityResult::NotVisible;
|
||||
}
|
||||
|
||||
if (Target.SightTargetInterface != nullptr)
|
||||
if (IAISightTargetInterface* SightTargetInterface = Target.WeakSightTargetInterface.Get())
|
||||
{
|
||||
const bool bWasVisible = SightQuery.GetLastResult();
|
||||
|
||||
|
@ -620,7 +620,7 @@ UAISense_Sight::EVisibilityResult UAISense_Sight_VR::ComputeVisibility(UWorld* W
|
|||
Context.IgnoreActor = ListenerActor;
|
||||
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)
|
||||
{
|
||||
// we need to clear the trace info value in order to avoid interfering with the engine processed asynchronous queries
|
||||
|
@ -842,38 +842,32 @@ void UAISense_Sight_VR::UnregisterSource(AActor& SourceActor)
|
|||
{
|
||||
AActor* TargetActor = AsTarget.Target.Get();
|
||||
|
||||
if (TargetActor)
|
||||
{
|
||||
// notify all interested observers that this source is no longer
|
||||
// visible
|
||||
AIPerception::FListenerMap& ListenersMap = *GetListeners();
|
||||
auto RemoveQuery = [this, &ListenersMap, &AsTargetId, &TargetActor](TArray<FAISightQueryVR>& SightQueries, const int32 QueryIndex)->EReverseForEachResult
|
||||
// notify all interested observers that this source is no longer
|
||||
// visible
|
||||
AIPerception::FListenerMap& ListenersMap = *GetListeners();
|
||||
auto RemoveQuery = [this, &ListenersMap, &AsTargetId, &TargetActor](TArray<FAISightQueryVR>& SightQueries, const int32 QueryIndex)->EReverseForEachResult
|
||||
{
|
||||
FAISightQueryVR* SightQuery = &SightQueries[QueryIndex];
|
||||
if (SightQuery->TargetId == AsTargetId)
|
||||
{
|
||||
if (SightQuery->GetLastResult())
|
||||
if (SightQuery->GetLastResult() && TargetActor)
|
||||
{
|
||||
FPerceptionListener& Listener = ListenersMap[SightQuery->ObserverId];
|
||||
ensure(Listener.Listener.IsValid());
|
||||
|
||||
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::UnTouched;
|
||||
};
|
||||
|
||||
ReverseForEach(SightQueriesInRange, RemoveQuery);
|
||||
if (ReverseForEach(SightQueriesOutOfRange, RemoveQuery) == EReverseForEachResult::Modified)
|
||||
{
|
||||
bSightQueriesOutOfRangeDirty = true;
|
||||
}
|
||||
ReverseForEach(SightQueriesPending, RemoveQuery);
|
||||
ReverseForEach(SightQueriesInRange, RemoveQuery);
|
||||
if (ReverseForEach(SightQueriesOutOfRange, RemoveQuery) == EReverseForEachResult::Modified)
|
||||
{
|
||||
bSightQueriesOutOfRangeDirty = true;
|
||||
}
|
||||
ReverseForEach(SightQueriesPending, RemoveQuery);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -883,20 +877,24 @@ bool UAISense_Sight_VR::RegisterTarget(AActor& TargetActor, const TFunction<void
|
|||
|
||||
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);
|
||||
|
||||
SightTarget = &(ObservedTargets.Add(NewSightTarget.TargetId, NewSightTarget));
|
||||
SightTarget->SightTargetInterface = Cast<IAISightTargetInterface>(&TargetActor);
|
||||
}
|
||||
else if (SightTarget == nullptr)
|
||||
{
|
||||
FAISightTargetVR NewSightTarget(&TargetActor);
|
||||
|
||||
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
|
||||
{
|
||||
SightTarget->WeakSightTargetInterface = Cast<IAISightTargetInterface>(&TargetActor);
|
||||
}
|
||||
}
|
||||
|
||||
// set/update data
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "SceneManagement.h"
|
||||
#include "Components/SkeletalMeshComponent.h"
|
||||
#include "PhysicsEngine/PhysicsAsset.h"
|
||||
#include "PhysicsEngine/ShapeElem.h"
|
||||
#include "PhysicsEngine/ConstraintInstance.h"
|
||||
#include "ReferenceSkeleton.h"
|
||||
#include "DrawDebugHelpers.h"
|
||||
|
|
|
@ -90,7 +90,7 @@ namespace
|
|||
|
||||
void RemoveWidget(UVRFullScreenUserWidget* InWidget)
|
||||
{
|
||||
WidgetsToHide.RemoveSingleSwap(InWidget, false);
|
||||
WidgetsToHide.RemoveSingleSwap(InWidget, EAllowShrinking::No);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -1645,7 +1645,7 @@ bool RLE_Funcs::RLEEncodeBuffer(DataType* BufferToEncode, uint32 EncodeLength, T
|
|||
|
||||
// Resize the out array to fit compressed contents
|
||||
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.
|
||||
// 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();
|
||||
|
||||
|
@ -462,7 +462,7 @@ void UReplicatedVRCameraComponent::HandleXRCamera()
|
|||
{
|
||||
FQuat Orientation;
|
||||
FVector Position;
|
||||
if (XRCamera->UpdatePlayerCamera(Orientation, Position))
|
||||
if (XRCamera->UpdatePlayerCamera(Orientation, Position, DeltaTime))
|
||||
{
|
||||
if (HasTrackingParameters())
|
||||
{
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "Net/UnrealNetwork.h"
|
||||
#include "XRMotionControllerBase.h"
|
||||
#include "NavFilters/NavigationQueryFilter.h"
|
||||
#include "Misc/EngineNetworkCustomVersion.h"
|
||||
//#include "Runtime/Engine/Private/EnginePrivate.h"
|
||||
|
||||
#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).
|
||||
// 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
|
||||
// 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.Rotation = ReplicatedMovementVR.Rotation;
|
||||
|
||||
ReppedMovement.ServerFrame = ReplicatedMovementVR.ServerFrame;
|
||||
ReppedMovement.ServerPhysicsHandle = ReplicatedMovementVR.ServerPhysicsHandle;
|
||||
ReppedMovement.bRepAcceleration = ReplicatedMovementVR.bRepAcceleration;
|
||||
ReppedMovement.Acceleration = ReplicatedMovementVR.Acceleration;
|
||||
|
||||
Super::OnRep_ReplicatedMovement();
|
||||
|
||||
if (!IsLocallyControlled())
|
||||
|
@ -469,8 +475,14 @@ void AVRBaseCharacter::GatherCurrentMovement()
|
|||
ReplicatedMovementVR.LinearVelocity = ReppedMovement.LinearVelocity;
|
||||
ReplicatedMovementVR.Location = ReppedMovement.Location;
|
||||
ReplicatedMovementVR.Rotation = ReppedMovement.Rotation;
|
||||
ReplicatedMovementVR.ServerFrame = ReppedMovement.ServerFrame;
|
||||
ReplicatedMovementVR.ServerPhysicsHandle = ReppedMovement.ServerPhysicsHandle;
|
||||
ReplicatedMovementVR.bRepAcceleration = ReppedMovement.bRepAcceleration;
|
||||
ReplicatedMovementVR.Acceleration = ReppedMovement.Acceleration;
|
||||
|
||||
ReplicatedMovementVR.bJustTeleported = bFlagTeleported;
|
||||
ReplicatedMovementVR.bJustTeleportedGrips = bFlagTeleportedGrips;
|
||||
|
||||
bFlagTeleported = false;
|
||||
bFlagTeleportedGrips = false;
|
||||
ReplicatedMovementVR.bPausedTracking = bTrackingPaused;
|
||||
|
@ -1001,7 +1013,7 @@ FVector AVRBaseCharacter::SetActorLocationAndRotationVR(FVector NewLoc, FRotator
|
|||
FVector AVRBaseCharacter::SetActorLocationVR(FVector NewLoc, bool bTeleport, bool bSetCapsuleLocation)
|
||||
{
|
||||
FVector NewLocation;
|
||||
FRotator NewRotation;
|
||||
//FRotator NewRotation;
|
||||
FVector PivotOffsetVal = (bSetCapsuleLocation ? GetVRLocation_Inline() : GetProjectedVRLocation()) - GetActorLocation();
|
||||
PivotOffsetVal.Z = 0.0f;
|
||||
|
||||
|
@ -1243,4 +1255,103 @@ void AVRBaseCharacter::SetVRReplicateCapsuleHeight(bool bNewVRReplicateCapsuleHe
|
|||
#if WITH_PUSH_MODEL
|
||||
MARK_PROPERTY_DIRTY_FROM_NAME(AVRBaseCharacter, VRReplicateCapsuleHeight, this);
|
||||
#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
|
||||
{
|
||||
if (AVRBaseCharacter * BaseCharacter = Cast<AVRBaseCharacter>(GetCharacterOwner()))
|
||||
|
||||
const UCapsuleComponent* const CapsuleComponent = CharacterOwner ? CharacterOwner->GetCapsuleComponent() : Cast<UCapsuleComponent>(UpdatedComponent);
|
||||
if (CapsuleComponent)
|
||||
{
|
||||
const float HalfHeight = CapsuleComponent->GetScaledCapsuleHalfHeight();
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
return UpdatedComponent ? (UpdatedComponent->GetComponentLocation() - FVector(0, 0, UpdatedComponent->Bounds.BoxExtent.Z)) : FNavigationSystem::InvalidLocation;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
@ -558,8 +577,8 @@ void UVRBaseCharacterMovementComponent::ComputeFloorDist(const FVector& CapsuleL
|
|||
if (DownwardSweepResult != NULL && DownwardSweepResult->IsValidBlockingHit())
|
||||
{
|
||||
// Only if the supplied sweep was vertical and downward.
|
||||
const bool bIsDownward = RotateWorldToGravity(DownwardSweepResult->TraceStart - DownwardSweepResult->TraceEnd).Z > 0;
|
||||
const bool bIsVertical = RotateWorldToGravity(DownwardSweepResult->TraceStart - DownwardSweepResult->TraceEnd).SizeSquared2D() <= UE_KINDA_SMALL_NUMBER;
|
||||
const bool bIsDownward = GetGravitySpaceZ(DownwardSweepResult->TraceStart - DownwardSweepResult->TraceEnd) > 0;
|
||||
const bool bIsVertical = ProjectToGravityFloor(DownwardSweepResult->TraceStart - DownwardSweepResult->TraceEnd).SizeSquared() <= UE_KINDA_SMALL_NUMBER;
|
||||
if (bIsDownward && bIsVertical)
|
||||
{
|
||||
// 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;
|
||||
|
||||
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);
|
||||
|
||||
if (bIsWalkable)
|
||||
|
@ -610,7 +629,7 @@ void UVRBaseCharacterMovementComponent::ComputeFloorDist(const FVector& CapsuleL
|
|||
FCollisionShape CapsuleShape = FCollisionShape::MakeCapsule(SweepRadius, PawnHalfHeight - ShrinkHeight);
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -628,7 +647,7 @@ void UVRBaseCharacterMovementComponent::ComputeFloorDist(const FVector& CapsuleL
|
|||
CapsuleShape.Capsule.HalfHeight = FMath::Max(PawnHalfHeight - ShrinkHeight, CapsuleShape.Capsule.Radius);
|
||||
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 FVector LineTraceStart = CapsuleLocation;
|
||||
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);
|
||||
|
||||
FHitResult Hit(1.f);
|
||||
|
@ -703,31 +722,32 @@ float UVRBaseCharacterMovementComponent::SlideAlongSurface(const FVector& Delta,
|
|||
return 0.f;
|
||||
}
|
||||
|
||||
FVector Normal(RotateWorldToGravity(InNormal));
|
||||
FVector Normal(InNormal);
|
||||
const FVector::FReal NormalZ = GetGravitySpaceZ(Normal);
|
||||
if (IsMovingOnGround())
|
||||
{
|
||||
// We don't want to be pushed up an unwalkable surface.
|
||||
if (Normal.Z > 0.f)
|
||||
if (NormalZ > 0.f)
|
||||
{
|
||||
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.
|
||||
if (CurrentFloor.FloorDist < MIN_FLOOR_DIST && CurrentFloor.bBlockingHit)
|
||||
{
|
||||
const FVector FloorNormal = RotateWorldToGravity(CurrentFloor.HitResult.Normal);
|
||||
const bool bFloorOpposedToMovement = (RotateWorldToGravity(Delta) | FloorNormal) < 0.f && (FloorNormal.Z < 1.f - UE_DELTA);
|
||||
const FVector FloorNormal = CurrentFloor.HitResult.Normal;
|
||||
const bool bFloorOpposedToMovement = (Delta | FloorNormal) < 0.f && (GetGravitySpaceZ(FloorNormal) < 1.f - UE_DELTA);
|
||||
|
||||
if (bFloorOpposedToMovement)
|
||||
{
|
||||
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.
|
||||
// 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))
|
||||
return Super::Super::SlideAlongSurface(Delta * VRWallSlideScaler, Time, RotateGravityToWorld(Normal), Hit, bHandleImpact);
|
||||
return Super::Super::SlideAlongSurface(Delta * VRWallSlideScaler, Time, Normal, Hit, bHandleImpact);
|
||||
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)
|
||||
|
@ -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.
|
||||
FVector NewToOldVector = (OldWorldLocation - NewWorldLocation);
|
||||
if (bIsNavWalkingOnServer && FMath::Abs(NewToOldVector.Z) < NavWalkingFloorDistTolerance)
|
||||
if (bIsNavWalkingOnServer && FMath::Abs(GetGravitySpaceZ(NewToOldVector)) < NavWalkingFloorDistTolerance)
|
||||
{
|
||||
// ignore smoothing on Z axis
|
||||
// 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
|
||||
NewToOldVector.Z = 0;
|
||||
NewToOldVector = ProjectToGravityFloor(NewToOldVector);
|
||||
}
|
||||
|
||||
const float DistSq = NewToOldVector.SizeSquared();
|
||||
|
|
|
@ -173,7 +173,7 @@ void UVRCharacterMovementComponent::Crouch(bool bClientSimulation)
|
|||
else
|
||||
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);
|
||||
|
||||
// If encroached, cancel
|
||||
|
@ -192,7 +192,7 @@ void UVRCharacterMovementComponent::Crouch(bool bClientSimulation)
|
|||
if (bCrouchMaintainsBaseLocation)
|
||||
{
|
||||
// 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;
|
||||
|
@ -219,7 +219,7 @@ void UVRCharacterMovementComponent::Crouch(bool bClientSimulation)
|
|||
|
||||
if (ClientData)
|
||||
{
|
||||
ClientData->MeshTranslationOffset -= FVector(0.f, 0.f, MeshAdjust);
|
||||
ClientData->MeshTranslationOffset -= MeshAdjust * -GetGravityDirection();
|
||||
ClientData->OriginalMeshTranslationOffset = ClientData->MeshTranslationOffset;
|
||||
}
|
||||
}
|
||||
|
@ -280,7 +280,7 @@ void UVRCharacterMovementComponent::UnCrouch(bool bClientSimulation)
|
|||
if (!bCrouchMaintainsBaseLocation)
|
||||
{
|
||||
// Expand in place
|
||||
bEncroached = MyWorld->OverlapBlockingTestByChannel(PawnLocation, FQuat::Identity, CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
|
||||
bEncroached = MyWorld->OverlapBlockingTestByChannel(PawnLocation, GetWorldToGravityTransform(), CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
|
||||
|
||||
if (bEncroached)
|
||||
{
|
||||
|
@ -292,11 +292,11 @@ void UVRCharacterMovementComponent::UnCrouch(bool bClientSimulation)
|
|||
CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnRadius, PawnHalfHeight);
|
||||
const float ShrinkHalfHeight = PawnHalfHeight - PawnRadius;
|
||||
const float TraceDist = PawnHalfHeight - ShrinkHalfHeight;
|
||||
const FVector Down = FVector(0.f, 0.f, -TraceDist);
|
||||
const FVector Down = TraceDist * GetGravityDirection();
|
||||
|
||||
FHitResult Hit(1.f);
|
||||
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)
|
||||
{
|
||||
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
|
||||
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);
|
||||
bEncroached = MyWorld->OverlapBlockingTestByChannel(NewLoc, FQuat::Identity, CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
|
||||
const FVector Adjustment = (-DistanceToBase + StandingCapsuleShape.Capsule.HalfHeight + SweepInflation + MIN_FLOOR_DIST / 2.f) * -GetGravityDirection();
|
||||
const FVector NewLoc = PawnLocation + Adjustment;
|
||||
bEncroached = MyWorld->OverlapBlockingTestByChannel(NewLoc, GetWorldToGravityTransform(), CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
|
||||
if (!bEncroached)
|
||||
{
|
||||
// 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
|
||||
{
|
||||
// Expand while keeping base location the same.
|
||||
FVector StandingLocation = PawnLocation + FVector(0.f, 0.f, StandingCapsuleShape.GetCapsuleHalfHeight() - CurrentCrouchedHalfHeight);
|
||||
bEncroached = MyWorld->OverlapBlockingTestByChannel(StandingLocation, FQuat::Identity, CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
|
||||
FVector StandingLocation = PawnLocation + (StandingCapsuleShape.GetCapsuleHalfHeight() - CurrentCrouchedHalfHeight) * -GetGravityDirection();
|
||||
bEncroached = MyWorld->OverlapBlockingTestByChannel(StandingLocation, GetWorldToGravityTransform(), CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
|
||||
|
||||
if (bEncroached)
|
||||
{
|
||||
|
@ -330,8 +331,8 @@ void UVRCharacterMovementComponent::UnCrouch(bool bClientSimulation)
|
|||
const float MinFloorDist = UE_KINDA_SMALL_NUMBER * 10.f;
|
||||
if (CurrentFloor.bBlockingHit && CurrentFloor.FloorDist > MinFloorDist)
|
||||
{
|
||||
StandingLocation.Z -= CurrentFloor.FloorDist - MinFloorDist;
|
||||
bEncroached = MyWorld->OverlapBlockingTestByChannel(StandingLocation, FQuat::Identity, CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
|
||||
StandingLocation -= (CurrentFloor.FloorDist - MinFloorDist) * -GetGravityDirection();
|
||||
bEncroached = MyWorld->OverlapBlockingTestByChannel(StandingLocation, GetWorldToGravityTransform(), CollisionChannel, StandingCapsuleShape, CapsuleParams, ResponseParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -375,7 +376,7 @@ void UVRCharacterMovementComponent::UnCrouch(bool bClientSimulation)
|
|||
|
||||
if (ClientData)
|
||||
{
|
||||
ClientData->MeshTranslationOffset += FVector(0.f, 0.f, MeshAdjust);
|
||||
ClientData->MeshTranslationOffset += MeshAdjust * -GetGravityDirection();
|
||||
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.
|
||||
// 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();
|
||||
if (VRRootCapsule)
|
||||
|
@ -932,8 +933,12 @@ void UVRCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iteration
|
|||
const FVector OldVelocity = Velocity;
|
||||
Acceleration = FVector::VectorPlaneProject(Acceleration, -GetGravityDirection());
|
||||
|
||||
|
||||
static const auto CVarLedgeMovementApplyDirectMove = IConsoleManager::Get().FindConsoleVariable(TEXT("p.LedgeMovement.ApplyDirectMove"));
|
||||
|
||||
// Apply acceleration
|
||||
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
|
||||
const bool bSkipForLedgeMove = bTriedLedgeMove && CVarLedgeMovementApplyDirectMove->GetBool();
|
||||
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && !bSkipForLedgeMove)
|
||||
{
|
||||
CalcVelocity(timeTick, GroundFriction, false, GetMaxBrakingDeceleration());
|
||||
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();
|
||||
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));
|
||||
}
|
||||
RestorePreAdditiveVRMotionVelocity();
|
||||
|
@ -1024,8 +1029,10 @@ void UVRCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iteration
|
|||
if (bCheckLedges && !CurrentFloor.IsWalkableFloor())
|
||||
{
|
||||
// calculate possible alternate movement
|
||||
const FVector GravDir = GetGravityDirection();
|
||||
const FVector NewDelta = bTriedLedgeMove ? FVector::ZeroVector : GetLedgeMove(OldCapsuleLocation, Delta, GravDir);
|
||||
const FVector NewDelta = bTriedLedgeMove ? FVector::ZeroVector : GetLedgeMove(OldLocation, Delta, OldFloor);
|
||||
// REMOVED 5.5 and replaced with above
|
||||
//const FVector GravDir = GetGravityDirection();
|
||||
//const FVector NewDelta = bTriedLedgeMove ? FVector::ZeroVector : GetLedgeMove(OldCapsuleLocation, Delta, GravDir);
|
||||
if (!NewDelta.IsZero())
|
||||
{
|
||||
// first revert this move
|
||||
|
@ -1037,6 +1044,7 @@ void UVRCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iteration
|
|||
// Try new movement direction
|
||||
Velocity = NewDelta / timeTick;
|
||||
remainingTime += timeTick;
|
||||
Iterations--;
|
||||
RestorePreAdditiveVRMotionVelocity();
|
||||
continue;
|
||||
}
|
||||
|
@ -1084,7 +1092,7 @@ void UVRCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iteration
|
|||
// 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.
|
||||
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);
|
||||
ResolvePenetration(RequestedAdjustment, Hit, UpdatedComponent->GetComponentQuat());
|
||||
bForceNextFloorCheck = true;
|
||||
|
@ -1168,8 +1176,10 @@ void UVRCharacterMovementComponent::CapsuleTouched(UPrimitiveComponent* Overlapp
|
|||
}
|
||||
|
||||
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();
|
||||
|
||||
FName BoneName = NAME_None;
|
||||
|
@ -1186,7 +1196,7 @@ void UVRCharacterMovementComponent::CapsuleTouched(UPrimitiveComponent* Overlapp
|
|||
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,
|
||||
MaxTouchForce > 0.0f ? MaxTouchForce : FLT_MAX);
|
||||
|
||||
|
@ -1541,7 +1551,7 @@ void UVRCharacterMovementComponent::ApplyRepulsionForce(float DeltaSeconds)
|
|||
// Trace to get the hit location on the capsule
|
||||
FHitResult Hit;
|
||||
bool bHasHit = UpdatedPrimitive->LineTraceComponent(Hit, BodyLocation,
|
||||
FVector(MyLocation.X, MyLocation.Y, BodyLocation.Z),
|
||||
ProjectToGravityFloor(MyLocation) + GetGravitySpaceComponentZ(BodyLocation),
|
||||
QueryParams);
|
||||
|
||||
FVector HitLoc = Hit.ImpactPoint;
|
||||
|
@ -1554,12 +1564,12 @@ void UVRCharacterMovementComponent::ApplyRepulsionForce(float DeltaSeconds)
|
|||
bIsPenetrating = true;
|
||||
}
|
||||
|
||||
const float DistanceNow = (HitLoc - BodyLocation).SizeSquared2D();
|
||||
const float DistanceLater = (HitLoc - (BodyLocation + BodyVelocity * DeltaSeconds)).SizeSquared2D();
|
||||
const float DistanceNow = ProjectToGravityFloor(HitLoc - BodyLocation).SizeSquared();
|
||||
const float DistanceLater = ProjectToGravityFloor(HitLoc - (BodyLocation + BodyVelocity * DeltaSeconds)).SizeSquared();
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -1567,11 +1577,12 @@ void UVRCharacterMovementComponent::ApplyRepulsionForce(float DeltaSeconds)
|
|||
|
||||
if (bHasHit)
|
||||
{
|
||||
ForceCenter.Z = HitLoc.Z;
|
||||
SetGravitySpaceZ(ForceCenter, GetGravitySpaceZ(HitLoc));
|
||||
}
|
||||
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);
|
||||
|
@ -1650,7 +1661,7 @@ void UVRCharacterMovementComponent::MoveAlongFloor(const FVector& InVelocity, fl
|
|||
}
|
||||
|
||||
// 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);
|
||||
FVector RampVector = ComputeGroundMovementDelta(Delta, CurrentFloor.HitResult, CurrentFloor.bLineTrace);
|
||||
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).
|
||||
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.
|
||||
const float InitialPercentRemaining = 1.f - PercentTimeApplied;
|
||||
|
@ -1691,8 +1702,7 @@ void UVRCharacterMovementComponent::MoveAlongFloor(const FVector& InVelocity, fl
|
|||
const FVector PreStepUpLocation = UpdatedComponent->GetComponentLocation();
|
||||
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(GravDir, (Delta * (1.f - PercentTimeApplied)) /*+ AdditionalVRInputVector.GetSafeNormal2D()*/, Hit, OutStepDownResult))
|
||||
if (!StepUp(GetGravityDirection(), Delta * (1.f - PercentTimeApplied), Hit, OutStepDownResult))
|
||||
{
|
||||
UE_LOG(LogVRCharacterMovement, Verbose, TEXT("- StepUp (ImpactNormal %s, Normal %s"), *Hit.ImpactNormal.ToString(), *Hit.Normal.ToString());
|
||||
HandleImpact(Hit, LastMoveTimeSlice, RampVector);
|
||||
|
@ -1710,7 +1720,7 @@ void UVRCharacterMovementComponent::MoveAlongFloor(const FVector& InVelocity, fl
|
|||
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && StepUpTimeSlice >= UE_KINDA_SMALL_NUMBER)
|
||||
{
|
||||
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);
|
||||
|
||||
// Don't bother stepping up if top of capsule is hitting something.
|
||||
const float InitialImpactZ = InHit.ImpactPoint.Z;
|
||||
if (InitialImpactZ > OldLocation.Z + (PawnHalfHeight - PawnRadius))
|
||||
const float InitialImpactZ = InHit.ImpactPoint | -GravDir;
|
||||
const float OldLocationZ = OldLocation | -GravDir;
|
||||
if (InitialImpactZ > OldLocationZ + (PawnHalfHeight - PawnRadius))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1762,7 +1773,7 @@ bool UVRCharacterMovementComponent::StepUp(const FVector& GravDir, const FVector
|
|||
float StepTravelUpHeight = MaxStepHeight;
|
||||
float StepTravelDownHeight = StepTravelUpHeight;
|
||||
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;
|
||||
|
||||
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);
|
||||
if (!CurrentFloor.bLineTrace && !bHitVerticalFace)
|
||||
{
|
||||
PawnFloorPointZ = CurrentFloor.HitResult.ImpactPoint.Z;
|
||||
PawnFloorPointZ = CurrentFloor.HitResult.ImpactPoint | -GravDir;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1868,7 +1879,7 @@ bool UVRCharacterMovementComponent::StepUp(const FVector& GravDir, const FVector
|
|||
if (Hit.IsValidBlockingHit())
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
//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.
|
||||
// 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());
|
||||
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.
|
||||
// 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).
|
||||
// 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);
|
||||
|
||||
// Don't bother stepping up if top of capsule is hitting something.
|
||||
const float InitialImpactZ = InHit.ImpactPoint.Z;
|
||||
if (InitialImpactZ > OldLocation.Z + (PawnHalfHeight - PawnRadius))
|
||||
const float InitialImpactZ = InHit.ImpactPoint | -GravDir;
|
||||
const float OldLocationZ = OldLocation | -GravDir;
|
||||
if (InitialImpactZ > OldLocationZ + (PawnHalfHeight - PawnRadius))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -2013,7 +2025,7 @@ bool UVRCharacterMovementComponent::VRClimbStepUp(const FVector& GravDir, const
|
|||
float StepTravelUpHeight = MaxStepHeight;
|
||||
float StepTravelDownHeight = StepTravelUpHeight;
|
||||
const float StepSideZ = -1.f * (InHit.ImpactNormal | GravDir);
|
||||
float PawnInitialFloorBaseZ = OldLocation.Z - PawnHalfHeight;
|
||||
float PawnInitialFloorBaseZ = OldLocationZ - PawnHalfHeight;
|
||||
float PawnFloorPointZ = PawnInitialFloorBaseZ;
|
||||
|
||||
// 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())
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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.
|
||||
// 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());
|
||||
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.
|
||||
// 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).
|
||||
// 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;
|
||||
}
|
||||
|
||||
FVector UVRCharacterMovementComponent::GetActorFeetLocation() const
|
||||
{
|
||||
// Call into the VR version of it instead
|
||||
return GetActorFeetLocationVR();
|
||||
}
|
||||
|
||||
|
||||
void UVRCharacterMovementComponent::UpdateBasedMovement(float DeltaSeconds)
|
||||
{
|
||||
|
@ -2259,8 +2277,12 @@ void UVRCharacterMovementComponent::UpdateBasedMovement(float DeltaSeconds)
|
|||
// @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))
|
||||
{
|
||||
TargetRotator.Pitch = 0.f;
|
||||
TargetRotator.Roll = 0.f;
|
||||
// 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.Roll = 0.f;
|
||||
}
|
||||
MoveUpdatedComponent(FVector::ZeroVector, TargetRotator, false);
|
||||
FinalQuat = UpdatedComponent->GetComponentQuat();
|
||||
}
|
||||
|
@ -2276,19 +2298,31 @@ void UVRCharacterMovementComponent::UpdateBasedMovement(float DeltaSeconds)
|
|||
}
|
||||
}
|
||||
|
||||
// We need to offset the base of the character here, not its origin, so offset by half height
|
||||
float HalfHeight, Radius;
|
||||
CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(Radius, HalfHeight);
|
||||
|
||||
if (!BaseVRCharacterOwner || BaseVRCharacterOwner->bRetainRoomscale)
|
||||
FVector NewWorldPos;
|
||||
if (HasCustomGravity())
|
||||
{
|
||||
HalfHeight = 0;
|
||||
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
|
||||
float HalfHeight, Radius;
|
||||
CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(Radius, HalfHeight);
|
||||
|
||||
FVector const BaseOffset(0.0f, 0.0f, HalfHeight);
|
||||
if (!BaseVRCharacterOwner || BaseVRCharacterOwner->bRetainRoomscale)
|
||||
{
|
||||
HalfHeight = 0;
|
||||
}
|
||||
|
||||
FVector const LocalBasePos = OldLocalToWorld.InverseTransformPosition(UpdatedComponent->GetComponentLocation() - BaseOffset);
|
||||
FVector const NewWorldPos = ConstrainLocationToPlane(NewLocalToWorld.TransformPosition(LocalBasePos) + BaseOffset);
|
||||
FVector const BaseOffset(0.0f, 0.0f, HalfHeight);
|
||||
|
||||
FVector const LocalBasePos = OldLocalToWorld.InverseTransformPosition(UpdatedComponent->GetComponentLocation() - BaseOffset);
|
||||
NewWorldPos = ConstrainLocationToPlane(NewLocalToWorld.TransformPosition(LocalBasePos) + BaseOffset);
|
||||
}
|
||||
|
||||
DeltaPosition = ConstrainDirectionToPlane(NewWorldPos - UpdatedComponent->GetComponentLocation());
|
||||
|
||||
// move attached actor
|
||||
|
@ -2377,16 +2411,13 @@ FVector UVRCharacterMovementComponent::GetImpartedMovementBaseVelocity() const
|
|||
if (bImpartBaseAngularVelocity)
|
||||
{
|
||||
// Base position should be the bottom of the actor since I offset the capsule now
|
||||
|
||||
float HalfHeight = CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
|
||||
if (!BaseVRCharacterOwner || BaseVRCharacterOwner->bRetainRoomscale)
|
||||
if (BaseVRCharacterOwner && BaseVRCharacterOwner->bRetainRoomscale)
|
||||
{
|
||||
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);
|
||||
BaseVelocity += BaseTangentialVel;
|
||||
}
|
||||
|
@ -2562,13 +2593,13 @@ float UVRCharacterMovementComponent::ImmersionDepth() const
|
|||
|
||||
if (VRRootCapsule)
|
||||
{
|
||||
TraceStart = VRRootCapsule->OffsetComponentToWorld.GetLocation() + FVector(0.f, 0.f, CollisionHalfHeight);
|
||||
TraceEnd = VRRootCapsule->OffsetComponentToWorld.GetLocation() - FVector(0.f, 0.f, CollisionHalfHeight);
|
||||
TraceStart = VRRootCapsule->OffsetComponentToWorld.GetLocation() + CollisionHalfHeight * -GetGravityDirection();
|
||||
TraceEnd = VRRootCapsule->OffsetComponentToWorld.GetLocation() - CollisionHalfHeight * -GetGravityDirection();
|
||||
}
|
||||
else
|
||||
{
|
||||
TraceStart = UpdatedComponent->GetComponentLocation() + FVector(0.f, 0.f, CollisionHalfHeight);
|
||||
TraceEnd = UpdatedComponent->GetComponentLocation() -FVector(0.f, 0.f, CollisionHalfHeight);
|
||||
TraceStart = UpdatedComponent->GetComponentLocation() + CollisionHalfHeight * -GetGravityDirection();
|
||||
TraceEnd = UpdatedComponent->GetComponentLocation() - CollisionHalfHeight * -GetGravityDirection();
|
||||
}
|
||||
|
||||
FCollisionQueryParams NewTraceParams(CharacterMovementComponentStatics::ImmersionDepthName, true);
|
||||
|
@ -2669,18 +2700,19 @@ void UVRCharacterMovementComponent::PhysFlying(float deltaTime, int32 Iterations
|
|||
|
||||
if (Hit.Time < 1.f)
|
||||
{
|
||||
const FVector GravDir = FVector(0.f, 0.f, -1.f);
|
||||
const FVector VelDir = Velocity.GetSafeNormal();
|
||||
const float UpDown = GravDir | VelDir;
|
||||
const float UpDown = VelDir | GetGravityDirection();
|
||||
|
||||
|
||||
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;
|
||||
bSteppedUp = StepUp(GravDir, (Adjusted + AdditionalVRInputVector) * (1.f - Hit.Time) /*+ AdditionalVRInputVector.GetSafeNormal2D()*/, Hit, nullptr);
|
||||
const FVector::FReal StepZ = GetGravitySpaceZ(UpdatedComponent->GetComponentLocation());
|
||||
bSteppedUp = StepUp(GetGravityDirection(), (Adjusted + AdditionalVRInputVector) * (1.f - Hit.Time), Hit);
|
||||
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;
|
||||
}
|
||||
|
||||
FVector FallAcceleration = GetFallingLateralAcceleration(deltaTime);
|
||||
const FVector GravityRelativeFallAcceleration = RotateWorldToGravity(FallAcceleration);
|
||||
FallAcceleration = RotateGravityToWorld(FVector(GravityRelativeFallAcceleration.X, GravityRelativeFallAcceleration.Y, 0));
|
||||
const FVector FallAcceleration = ProjectToGravityFloor(GetFallingLateralAcceleration(deltaTime));
|
||||
const bool bHasLimitedAirControl = ShouldLimitAirControl(deltaTime, FallAcceleration);
|
||||
|
||||
// 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);
|
||||
if (HasCustomGravity())
|
||||
{
|
||||
Velocity = FVector::VectorPlaneProject(Velocity, RotateGravityToWorld(FVector::UpVector));
|
||||
Velocity = ProjectToGravityFloor(Velocity);
|
||||
const FVector GravityRelativeOffset = OldVelocity - Velocity;
|
||||
CalcVelocity(timeTick, FallingLateralFriction, false, MaxDecel);
|
||||
Velocity += GravityRelativeOffset;
|
||||
|
@ -2797,15 +2827,15 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
|||
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.
|
||||
const FVector GravityRelativeOldVelocityWithRootMotion = RotateWorldToGravity(OldVelocityWithRootMotion);
|
||||
const FVector::FReal GravityRelativeOldVelocityWithRootMotionZ = GetGravitySpaceZ(OldVelocityWithRootMotion);
|
||||
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 GravityRelativeDerivedAccel = RotateWorldToGravity(DerivedAccel);
|
||||
if (!FMath::IsNearlyZero(GravityRelativeDerivedAccel.Z))
|
||||
const FVector::FReal GravityRelativeDerivedAccelZ = GetGravitySpaceZ(DerivedAccel);
|
||||
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.
|
||||
const float ApexTimeMinimum = 0.0001f;
|
||||
|
@ -2814,8 +2844,7 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
|||
const FVector ApexVelocity = OldVelocityWithRootMotion + (DerivedAccel * TimeToApex);
|
||||
if (HasCustomGravity())
|
||||
{
|
||||
const FVector GravityRelativeApexVelocity = RotateWorldToGravity(ApexVelocity);
|
||||
Velocity = RotateGravityToWorld(FVector(GravityRelativeApexVelocity.X, GravityRelativeApexVelocity.Y, 0)); // Should be nearly zero anyway, but this makes apex notifications consistent.
|
||||
Velocity = ProjectToGravityFloor(ApexVelocity); // Should be nearly zero anyway, but this makes apex notifications consistent.
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2847,7 +2876,7 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
|||
ApplyRootMotionToVelocity(timeTick);
|
||||
//ApplyVRMotionToVelocity(deltaTime);
|
||||
|
||||
if (bNotifyApex && (RotateWorldToGravity(Velocity).Z < 0.f))
|
||||
if (bNotifyApex && (GetGravitySpaceZ(Velocity) < 0.f))
|
||||
{
|
||||
// Just passed jump apex since now going down
|
||||
bNotifyApex = false;
|
||||
|
@ -2912,7 +2941,9 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
|||
|
||||
FFindFloorResult FloorResult;
|
||||
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();
|
||||
remainingTime += subTimeTickRemaining;
|
||||
|
@ -2950,7 +2981,7 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
|||
TGuardValue<FVector> RestoreVelocity(Velocity, OldVelocity);
|
||||
if (HasCustomGravity())
|
||||
{
|
||||
Velocity = FVector::VectorPlaneProject(Velocity, RotateGravityToWorld(FVector::UpVector));
|
||||
Velocity = ProjectToGravityFloor(Velocity);
|
||||
const FVector GravityRelativeOffset = OldVelocity - Velocity;
|
||||
CalcVelocity(timeTick, FallingLateralFriction, false, MaxDecel);
|
||||
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 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)
|
||||
{
|
||||
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)
|
||||
|
@ -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.
|
||||
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;
|
||||
Delta = ComputeSlideVector(LastMoveNoAirControl, 1.f, OldHitNormal, Hit);
|
||||
|
@ -3045,19 +3076,27 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
|||
if (subTimeTickRemaining > UE_KINDA_SMALL_NUMBER && !bJustTeleported)
|
||||
{
|
||||
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
|
||||
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);
|
||||
if (Hit.Time == 0.f)
|
||||
{
|
||||
// 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())
|
||||
{
|
||||
SideDelta = FVector(OldHitNormal.Y, -OldHitNormal.X, 0).GetSafeNormal();
|
||||
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();
|
||||
}
|
||||
}
|
||||
SafeMoveUpdatedComponent(SideDelta, PawnRotation, true, Hit);
|
||||
}
|
||||
|
@ -3069,13 +3108,13 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
|||
ProcessLanded(Hit, remainingTime, Iterations);
|
||||
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.
|
||||
const FVector PawnLocation = UpdatedComponent->GetComponentLocation();
|
||||
const float ZMovedDist = FMath::Abs(RotateWorldToGravity(PawnLocation - OldLocation).Z);
|
||||
const float MovedDist2DSq = FVector::VectorPlaneProject(PawnLocation - OldLocation, RotateGravityToWorld(FVector::UpVector)).Size2D();
|
||||
if (ZMovedDist <= 0.2f * timeTick && MovedDist2DSq <= 4.f * timeTick)
|
||||
const float ZMovedDist = FMath::Abs(GetGravitySpaceZ(PawnLocation - OldLocation));
|
||||
const float MovedDist2D = ProjectToGravityFloor(PawnLocation - OldLocation).Size();
|
||||
if (ZMovedDist <= 0.2f * timeTick && MovedDist2D <= 4.f * timeTick)
|
||||
{
|
||||
FVector GravityRelativeVelocity = RotateWorldToGravity(Velocity);
|
||||
GravityRelativeVelocity.X += 0.25f * GetMaxSpeed() * (RandomStream.FRand() - 0.5f);
|
||||
|
@ -3135,12 +3174,10 @@ void UVRCharacterMovementComponent::PhysFalling(float deltaTime, int32 Iteration
|
|||
}
|
||||
}
|
||||
|
||||
FVector GravityRelativeVelocity = RotateWorldToGravity(Velocity);
|
||||
if (GravityRelativeVelocity.SizeSquared2D() <= UE_KINDA_SMALL_NUMBER * 10.f)
|
||||
const FVector GravityProjectedVelocity = ProjectToGravityFloor(Velocity);
|
||||
if (GravityProjectedVelocity.SizeSquared() <= UE_KINDA_SMALL_NUMBER * 10.f)
|
||||
{
|
||||
GravityRelativeVelocity.X = 0.f;
|
||||
GravityRelativeVelocity.Y = 0.f;
|
||||
Velocity = RotateGravityToWorld(GravityRelativeVelocity);
|
||||
Velocity = GetGravitySpaceComponentZ(Velocity);
|
||||
}
|
||||
|
||||
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()));
|
||||
|
||||
//bound acceleration
|
||||
Acceleration.Z = 0.f;
|
||||
Acceleration = ProjectToGravityFloor(Acceleration);
|
||||
//if (!HasRootMotion())
|
||||
//{
|
||||
CalcVelocity(deltaTime, GroundFriction, false, BrakingDecelerationWalking);
|
||||
|
@ -3198,8 +3235,7 @@ void UVRCharacterMovementComponent::PhysNavWalking(float deltaTime, int32 Iterat
|
|||
|
||||
Iterations++;
|
||||
|
||||
FVector DesiredMove = Velocity;
|
||||
DesiredMove.Z = 0.f;
|
||||
const FVector DesiredMove = ProjectToGravityFloor(Velocity);
|
||||
|
||||
//const FVector OldPlayerLocation = GetActorFeetLocation();
|
||||
const FVector OldLocation = GetActorFeetLocationVR();
|
||||
|
@ -3214,11 +3250,11 @@ void UVRCharacterMovementComponent::PhysNavWalking(float deltaTime, int32 Iterat
|
|||
{
|
||||
if (bProjectNavMeshWalking)
|
||||
{
|
||||
const float DistSq2D = (OldLocation - CachedNavLocation.Location).SizeSquared2D();
|
||||
const float DistZ = FMath::Abs(OldLocation.Z - CachedNavLocation.Location.Z);
|
||||
const float DistSq2D = ProjectToGravityFloor(OldLocation - CachedNavLocation.Location).SizeSquared();
|
||||
const float DistZ = FMath::Abs(GetGravitySpaceZ(OldLocation - CachedNavLocation.Location));
|
||||
|
||||
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);
|
||||
|
||||
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.
|
||||
if (bSameNavLocation && bProjectNavMeshWalking)
|
||||
{
|
||||
AdjustedDest.Z = CachedNavLocation.Location.Z;
|
||||
SetGravitySpaceZ(AdjustedDest, GetGravitySpaceZ(CachedNavLocation.Location));
|
||||
}
|
||||
|
||||
// Find the point on the NavMesh
|
||||
|
@ -3272,7 +3308,7 @@ void UVRCharacterMovementComponent::PhysNavWalking(float deltaTime, int32 Iterat
|
|||
|
||||
if (DestNavLocation.NodeRef != INVALID_NAVNODEREF)
|
||||
{
|
||||
FVector NewLocation(AdjustedDest.X, AdjustedDest.Y, DestNavLocation.Location.Z);
|
||||
FVector NewLocation = ProjectToGravityFloor(AdjustedDest) + GetGravitySpaceComponentZ(DestNavLocation.Location);
|
||||
if (bProjectNavMeshWalking)
|
||||
{
|
||||
SCOPE_CYCLE_COUNTER(STAT_CharNavProjectLocation);
|
||||
|
@ -3330,18 +3366,18 @@ void UVRCharacterMovementComponent::PhysSwimming(float deltaTime, int32 Iteratio
|
|||
float NetFluidFriction = 0.f;
|
||||
float Depth = ImmersionDepth();
|
||||
float NetBuoyancy = Buoyancy * Depth;
|
||||
float OriginalAccelZ = Acceleration.Z;
|
||||
float OriginalAccelZ = GetGravitySpaceZ(Acceleration);
|
||||
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
|
||||
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)
|
||||
{
|
||||
bLimitedUpAccel = (Acceleration.Z > 0.f);
|
||||
Acceleration.Z = FMath::Min<FVector::FReal>(0.1f, Acceleration.Z);
|
||||
bLimitedUpAccel = (OriginalAccelZ > 0.f);
|
||||
SetGravitySpaceZ(Acceleration, FMath::Min<FVector::FReal>(0.1f, OriginalAccelZ));
|
||||
}
|
||||
|
||||
Iterations++;
|
||||
|
@ -3351,7 +3387,7 @@ void UVRCharacterMovementComponent::PhysSwimming(float deltaTime, int32 Iteratio
|
|||
{
|
||||
const float Friction = 0.5f * GetPhysicsVolume()->FluidFriction * Depth;
|
||||
CalcVelocity(deltaTime, Friction, true, GetMaxBrakingDeceleration());
|
||||
Velocity.Z += GetGravityZ() * deltaTime * (1.f - NetBuoyancy);
|
||||
Velocity += (GetGravityZ() * deltaTime * (1.f - NetBuoyancy)) * -GetGravityDirection();
|
||||
}
|
||||
|
||||
ApplyRootMotionToVelocity(deltaTime);
|
||||
|
@ -3359,7 +3395,7 @@ void UVRCharacterMovementComponent::PhysSwimming(float deltaTime, int32 Iteratio
|
|||
|
||||
FVector Adjusted = Velocity * deltaTime;
|
||||
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
|
||||
if (!IsSwimming())
|
||||
|
@ -3372,10 +3408,10 @@ void UVRCharacterMovementComponent::PhysSwimming(float deltaTime, int32 Iteratio
|
|||
if (Hit.Time < 1.f && CharacterOwner)
|
||||
{
|
||||
HandleSwimmingWallHit(Hit, deltaTime);
|
||||
if (bLimitedUpAccel && (Velocity.Z >= 0.f))
|
||||
if (bLimitedUpAccel && (GetGravitySpaceZ(Velocity) >= 0.f))
|
||||
{
|
||||
// allow upward velocity at surface if against obstacle
|
||||
Velocity.Z += OriginalAccelZ * deltaTime;
|
||||
Velocity += OriginalAccelZ * deltaTime * -GetGravityDirection();
|
||||
Adjusted = Velocity * (1.f - Hit.Time)*deltaTime;
|
||||
SwimVR(Adjusted, Hit);
|
||||
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 float UpDown = GravDir | VelDir;
|
||||
const float UpDown = VelDir | GetGravityDirection();
|
||||
|
||||
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;
|
||||
Velocity.Z = 1.f; // HACK: since will be moving up, in case pawn leaves the water
|
||||
bSteppedUp = StepUp(GravDir, (Adjusted/* + AdditionalVRInputVector*/) * (1.f - Hit.Time), Hit);
|
||||
SetGravitySpaceZ(Velocity, 1.f); // HACK: since will be moving up, in case pawn leaves the water
|
||||
bSteppedUp = StepUp(GetGravityDirection(), Adjusted * (1.f - Hit.Time), Hit);
|
||||
if (bSteppedUp)
|
||||
{
|
||||
//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);
|
||||
return;
|
||||
}
|
||||
OldLocation.Z = UpdatedComponent->GetComponentLocation().Z + (OldLocation.Z - stepZ);
|
||||
SetGravitySpaceZ(OldLocation, GetGravitySpaceZ(UpdatedComponent->GetComponentLocation()) + (GetGravitySpaceZ(OldLocation) - StepZ));
|
||||
}
|
||||
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)
|
||||
{
|
||||
bool bWaterJump = !GetPhysicsVolume()->bWaterVolume;
|
||||
float velZ = Velocity.Z;
|
||||
const bool bWaterJump = !GetPhysicsVolume()->bWaterVolume;
|
||||
const FVector::FReal VelZ = GetGravitySpaceZ(Velocity);
|
||||
Velocity = ((UpdatedComponent->GetComponentLocation() - OldLocation)/* - AdditionalVRInputVector*/) / (deltaTime - remainingTime);
|
||||
if (bWaterJump)
|
||||
{
|
||||
Velocity.Z = velZ;
|
||||
SetGravitySpaceZ(Velocity, VelZ);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3472,9 +3507,10 @@ void UVRCharacterMovementComponent::StartSwimmingVR(FVector OldLocation, FVector
|
|||
}
|
||||
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))
|
||||
{
|
||||
|
@ -3517,26 +3553,25 @@ bool UVRCharacterMovementComponent::CheckWaterJump(FVector CheckPoint, FVector&
|
|||
FVector currentLoc = VRRootCapsule ? VRRootCapsule->OffsetComponentToWorld.GetLocation() : UpdatedComponent->GetComponentLocation();
|
||||
|
||||
// check if there is a wall directly in front of the swimming pawn
|
||||
CheckPoint.Z = 0.f;
|
||||
CheckPoint = ProjectToGravityFloor(CheckPoint);
|
||||
FVector CheckNorm = CheckPoint.GetSafeNormal();
|
||||
float PawnCapsuleRadius, PawnCapsuleHalfHeight;
|
||||
CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleSize(PawnCapsuleRadius, PawnCapsuleHalfHeight);
|
||||
CheckPoint = currentLoc + 1.2f * PawnCapsuleRadius * CheckNorm;
|
||||
FVector Extent(PawnCapsuleRadius, PawnCapsuleRadius, PawnCapsuleHalfHeight);
|
||||
FHitResult HitInfo(1.f);
|
||||
FCollisionQueryParams CapsuleParams(SCENE_QUERY_STAT(CheckWaterJump), false, CharacterOwner);
|
||||
FCollisionResponseParams ResponseParam;
|
||||
InitCollisionParams(CapsuleParams, ResponseParam);
|
||||
FCollisionShape CapsuleShape = GetPawnCapsuleCollisionShape(SHRINK_None);
|
||||
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()))
|
||||
{
|
||||
// hit a wall - check if it is low enough
|
||||
WallNormal = -1.f * HitInfo.ImpactNormal;
|
||||
FVector Start = currentLoc;//UpdatedComponent->GetComponentLocation();
|
||||
Start.Z += MaxOutOfWaterStepHeight;
|
||||
Start += MaxOutOfWaterStepHeight * -GetGravityDirection();
|
||||
CheckPoint = Start + 3.2f * PawnCapsuleRadius * WallNormal;
|
||||
FCollisionQueryParams LineParams(SCENE_QUERY_STAT(CheckWaterJump), true, CharacterOwner);
|
||||
FCollisionResponseParams LineResponseParam;
|
||||
|
@ -3725,11 +3760,7 @@ void UVRCharacterMovementComponent::SimulateMovement(float DeltaSeconds)
|
|||
// find floor and check if falling
|
||||
if (IsMovingOnGround() || MovementMode == MOVE_Falling)
|
||||
{
|
||||
bool bShouldFindFloor = Velocity.Z <= 0.f;
|
||||
if (HasCustomGravity())
|
||||
{
|
||||
bShouldFindFloor = RotateWorldToGravity(Velocity).Z <= 0.0;
|
||||
}
|
||||
const bool bShouldFindFloor = GetGravitySpaceZ(Velocity) <= UE_KINDA_SMALL_NUMBER;
|
||||
|
||||
if (StepDownResult.bComputedFloor)
|
||||
{
|
||||
|
@ -3750,14 +3781,8 @@ void UVRCharacterMovementComponent::SimulateMovement(float DeltaSeconds)
|
|||
{
|
||||
// Follows PhysWalking approach for encroachment on floor tests
|
||||
FHitResult Hit(CurrentFloor.HitResult);
|
||||
if (HasCustomGravity())
|
||||
{
|
||||
Hit.TraceEnd = Hit.TraceStart - GetGravityDirection() * MAX_FLOOR_DIST;
|
||||
}
|
||||
else
|
||||
{
|
||||
Hit.TraceEnd = Hit.TraceStart + FVector(0.f, 0.f, MAX_FLOOR_DIST);
|
||||
}
|
||||
Hit.TraceEnd = Hit.TraceStart - GetGravityDirection() * MAX_FLOOR_DIST;
|
||||
|
||||
|
||||
const FVector RequestedAdjustment = GetPenetrationAdjustment(Hit);
|
||||
const bool bResolved = ResolvePenetration(RequestedAdjustment, Hit, UpdatedComponent->GetComponentQuat());
|
||||
|
@ -3775,16 +3800,9 @@ void UVRCharacterMovementComponent::SimulateMovement(float DeltaSeconds)
|
|||
if (!bSimGravityDisabled)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
else if (Velocity.Z <= 0.f || bApplyGravityWhileJumping || !CharacterOwner->IsJumpProvidingForce())
|
||||
{
|
||||
Velocity = NewFallVelocity(Velocity, FVector(0.f, 0.f, GetGravityZ()), DeltaSeconds);
|
||||
Velocity = NewFallVelocity(Velocity, -GetGravityDirection() * GetGravityZ(), DeltaSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3903,7 +3921,7 @@ void UVRCharacterMovementComponent::MoveSmooth(const FVector& InVelocity, const
|
|||
{
|
||||
OutStepDownResult = NULL; // No need for a floor when not walking.
|
||||
bool bShouldAttemptStepUp = false;
|
||||
bShouldAttemptStepUp = FMath::Abs(RotateWorldToGravity(Hit.ImpactNormal).Z) < 0.2;
|
||||
bShouldAttemptStepUp = FMath::Abs(GetGravitySpaceZ(Hit.ImpactNormal)) < 0.2;
|
||||
if (bShouldAttemptStepUp)
|
||||
{
|
||||
const FVector GravDir = GetGravityDirection();
|
||||
|
@ -3946,7 +3964,7 @@ void UVRCharacterMovementComponent::ClientHandleMoveResponse(const FCharacterMov
|
|||
MoveResponse.RootMotionTrackPosition,
|
||||
MoveResponse.ClientAdjustment.NewLoc,
|
||||
MoveResponse.RootMotionRotation,
|
||||
MoveResponse.ClientAdjustment.NewVel.Z,
|
||||
GetGravitySpaceZ(MoveResponse.ClientAdjustment.NewVel),
|
||||
MoveResponse.ClientAdjustment.NewBase,
|
||||
MoveResponse.ClientAdjustment.NewBaseBoneName,
|
||||
MoveResponse.bHasBase,
|
||||
|
@ -3961,7 +3979,7 @@ void UVRCharacterMovementComponent::ClientHandleMoveResponse(const FCharacterMov
|
|||
MoveResponse.RootMotionTrackPosition,
|
||||
MoveResponse.ClientAdjustment.NewLoc,
|
||||
MoveResponse.RootMotionRotation,
|
||||
MoveResponse.ClientAdjustment.NewVel.Z,
|
||||
GetGravitySpaceZ(MoveResponse.ClientAdjustment.NewVel),
|
||||
MoveResponse.ClientAdjustment.NewBase,
|
||||
MoveResponse.ClientAdjustment.NewBaseBoneName,
|
||||
MoveResponse.bHasBase,
|
||||
|
@ -4452,7 +4470,7 @@ void UVRCharacterMovementComponent::ServerMoveHandleClientErrorVR(float ClientTi
|
|||
{
|
||||
const FVector LastBaseVelocity = MovementBaseUtility::GetMovementBaseVelocity(LastServerMovementBaseVRPtr, LastServerMovementBaseBoneName);
|
||||
RelativeVelocity = Velocity - LastBaseVelocity;
|
||||
const FVector BaseDirection = LastBaseVelocity.GetSafeNormal2D();
|
||||
const FVector BaseDirection = ProjectToGravityFloor(LastBaseVelocity).GetSafeNormal();
|
||||
const FVector RelativeDirection = RelativeVelocity * (1.f / MaxWalkSpeed);
|
||||
|
||||
ClientForwardFactor = FMath::Clamp(FVector::DotProduct(BaseDirection, RelativeDirection), 0.f, 1.f);
|
||||
|
|
|
@ -245,7 +245,7 @@ void UVRGestureComponent::CaptureGestureFrame()
|
|||
// Pop off oldest sample
|
||||
if (GestureLog.Samples.Num() >= RecordingBufferSize)
|
||||
{
|
||||
GestureLog.Samples.Pop(false);
|
||||
GestureLog.Samples.Pop(EAllowShrinking::No);
|
||||
bClearLatestSpline = true;
|
||||
}
|
||||
|
||||
|
@ -600,8 +600,8 @@ bool UGesturesDatabase::ImportSplineAsGesture(USplineComponent * HostSplineCompo
|
|||
|
||||
float LastDistance = 0.f;
|
||||
float ThisDistance = 0.f;
|
||||
FVector LastDistanceV;
|
||||
FVector ThisDistanceV;
|
||||
FVector LastDistanceV = FVector::ZeroVector;
|
||||
FVector ThisDistanceV = FVector::ZeroVector;
|
||||
FVector DistNormal;
|
||||
float DistAlongSegment = 0.f;
|
||||
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
#include "VRPathFollowingComponent.h"
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(VRPathFollowingComponent)
|
||||
|
||||
#include "AI/Navigation/NavigationTypes.h"
|
||||
#include "AI/Navigation/PathFollowingAgentInterface.h"
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Engine/World.h"
|
||||
//#include "Runtime/Engine/Private/EnginePrivate.h"
|
||||
|
@ -16,7 +19,7 @@
|
|||
|
||||
DEFINE_LOG_CATEGORY(LogPathFollowingVR);
|
||||
|
||||
void UVRPathFollowingComponent::SetMovementComponent(UNavMovementComponent* MoveComp)
|
||||
/*void UVRPathFollowingComponent::SetMovementComponent(UNavMovementComponent* MoveComp)
|
||||
{
|
||||
Super::SetMovementComponent(MoveComp);
|
||||
|
||||
|
@ -26,8 +29,23 @@ void UVRPathFollowingComponent::SetMovementComponent(UNavMovementComponent* Move
|
|||
{
|
||||
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
|
||||
{
|
||||
|
@ -82,52 +100,8 @@ void UVRPathFollowingComponent::GetDebugStringTokens(TArray<FString>& Tokens, TA
|
|||
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()))
|
||||
{
|
||||
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 UVRPathFollowingComponent::DetermineStartingPathPoint(const FNavigationPath* ConsideredPath) const
|
||||
{
|
||||
int32 PickedPathPoint = INDEX_NONE;
|
||||
|
||||
|
@ -192,7 +166,7 @@ bool UVRPathFollowingComponent::UpdateBlockDetection()
|
|||
{
|
||||
LocationSamples.AddZeroed(1);
|
||||
}
|
||||
|
||||
|
||||
LocationSamples[NextSampleIdx] = (VRMovementComp != nullptr ? VRMovementComp->GetActorFeetLocationBased() : MovementComp->GetActorFeetLocationBased());
|
||||
NextSampleIdx = (NextSampleIdx + 1) % BlockDetectionSampleCount;
|
||||
return true;
|
||||
|
@ -302,8 +276,8 @@ void UVRPathFollowingComponent::UpdatePathSegment()
|
|||
if (Path->GetPathPoints().IsValidIndex(MoveSegmentEndIndex) && Path->GetPathPoints().IsValidIndex(MoveSegmentStartIndex))
|
||||
{
|
||||
//LogBlockHelper(GetOwner(), MovementComp, MinAgentRadiusPct, MinAgentHalfHeightPct,
|
||||
//*Path->GetPathPointLocation(MoveSegmentStartIndex),
|
||||
//*Path->GetPathPointLocation(MoveSegmentEndIndex));
|
||||
//Path->GetPathPointLocation(MoveSegmentStartIndex),
|
||||
//Path->GetPathPointLocation(MoveSegmentEndIndex));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -455,7 +429,7 @@ void UVRPathFollowingComponent::DebugReachTest(float& CurrentDot, float& Current
|
|||
|
||||
const FVector ToGoal = (GoalLocation - AgentLocation);
|
||||
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;
|
||||
|
||||
// get cylinder of moving agent
|
||||
|
@ -472,3 +446,4 @@ void UVRPathFollowingComponent::DebugReachTest(float& CurrentDot, float& Current
|
|||
const float UseHeight = GoalHalfHeight + (AgentHalfHeight * MinAgentHalfHeightPct);
|
||||
bHeightFailed = (CurrentHeight > UseHeight) ? 1 : 0;
|
||||
}
|
||||
*/
|
|
@ -862,7 +862,11 @@ public:
|
|||
{
|
||||
bWillEverBeLit = false;
|
||||
bCreateSceneProxy = InComponent->bShouldCreateProxy;
|
||||
MaterialRelevance = MaterialInstance->GetRelevance(GetScene().GetFeatureLevel());
|
||||
|
||||
if (MaterialInstance)
|
||||
{
|
||||
MaterialRelevance = MaterialInstance->GetRelevance(GetScene().GetFeatureLevel());
|
||||
}
|
||||
}
|
||||
|
||||
// FPrimitiveSceneProxy interface.
|
||||
|
@ -886,12 +890,12 @@ public:
|
|||
{
|
||||
ParentMaterialProxy = WireframeMaterialInstance;
|
||||
}
|
||||
else
|
||||
else if (MaterialInstance != nullptr)
|
||||
{
|
||||
ParentMaterialProxy = MaterialInstance->GetRenderProxy();
|
||||
}
|
||||
#else
|
||||
FMaterialRenderProxy* ParentMaterialProxy = MaterialInstance->GetRenderProxy();
|
||||
FMaterialRenderProxy* ParentMaterialProxy = MaterialInstance ? MaterialInstance->GetRenderProxy() : nullptr;
|
||||
#endif
|
||||
|
||||
//FSpriteTextureOverrideRenderProxy* TextureOverrideMaterialProxy = new FSpriteTextureOverrideRenderProxy(ParentMaterialProxy,
|
||||
|
@ -912,10 +916,10 @@ public:
|
|||
{
|
||||
if (GeometryMode == EWidgetGeometryMode::Plane)
|
||||
{
|
||||
float U = -RenderTarget->SizeX * Pivot.X;
|
||||
float V = -RenderTarget->SizeY * Pivot.Y;
|
||||
float UL = RenderTarget->SizeX * (1.0f - Pivot.X);
|
||||
float VL = RenderTarget->SizeY * (1.0f - Pivot.Y);
|
||||
float U = -RenderTarget->SizeX * static_cast<float>(Pivot.X);
|
||||
float V = -RenderTarget->SizeY * static_cast<float>(Pivot.Y);
|
||||
float UL = RenderTarget->SizeX * (1.0f - static_cast<float>(Pivot.X));
|
||||
float VL = RenderTarget->SizeY * (1.0f - static_cast<float>(Pivot.Y));
|
||||
|
||||
int32 VertexIndices[4];
|
||||
|
||||
|
@ -948,13 +952,13 @@ public:
|
|||
const int32 NumSegments = FMath::Lerp(4, 32, ArcAngle / PI);
|
||||
|
||||
|
||||
const float Radius = RenderTarget->SizeX / ArcAngle;
|
||||
const float Apothem = Radius * FMath::Cos(0.5f*ArcAngle);
|
||||
const float ChordLength = 2.0f * Radius * FMath::Sin(0.5f*ArcAngle);
|
||||
const double Radius = RenderTarget->SizeX / ArcAngle;
|
||||
const double Apothem = Radius * FMath::Cos(0.5 * ArcAngle);
|
||||
const double ChordLength = 2.0f * Radius * FMath::Sin(0.5 * ArcAngle);
|
||||
|
||||
const float PivotOffsetX = ChordLength * (0.5 - Pivot.X);
|
||||
const float V = -RenderTarget->SizeY * Pivot.Y;
|
||||
const float VL = RenderTarget->SizeY * (1.0f - Pivot.Y);
|
||||
const double PivotOffsetX = ChordLength * (0.5 - Pivot.X);
|
||||
const double V = -RenderTarget->SizeY * Pivot.Y;
|
||||
const double VL = RenderTarget->SizeY * (1.0 - Pivot.Y);
|
||||
|
||||
int32 VertexIndices[4];
|
||||
|
||||
|
@ -964,7 +968,7 @@ public:
|
|||
|
||||
if (VisibilityMap & (1 << ViewIndex))
|
||||
{
|
||||
const float RadiansPerStep = ArcAngle / NumSegments;
|
||||
const double RadiansPerStep = ArcAngle / NumSegments;
|
||||
|
||||
FVector LastTangentX;
|
||||
FVector LastTangentY;
|
||||
|
@ -972,14 +976,14 @@ public:
|
|||
|
||||
for (int32 Segment = 0; Segment < NumSegments; Segment++)
|
||||
{
|
||||
const float Angle = -ArcAngle / 2 + Segment * RadiansPerStep;
|
||||
const float NextAngle = Angle + RadiansPerStep;
|
||||
const double Angle = -ArcAngle / 2 + Segment * RadiansPerStep;
|
||||
const double NextAngle = Angle + RadiansPerStep;
|
||||
|
||||
// Polar to Cartesian
|
||||
const float X0 = Radius * FMath::Cos(Angle) - Apothem;
|
||||
const float Y0 = Radius * FMath::Sin(Angle);
|
||||
const float X1 = Radius * FMath::Cos(NextAngle) - Apothem;
|
||||
const float Y1 = Radius * FMath::Sin(NextAngle);
|
||||
const double X0 = Radius * FMath::Cos(Angle) - Apothem;
|
||||
const double Y0 = Radius * FMath::Sin(Angle);
|
||||
const double X1 = Radius * FMath::Cos(NextAngle) - Apothem;
|
||||
const double Y1 = Radius * FMath::Sin(NextAngle);
|
||||
|
||||
const float U0 = static_cast<float>(Segment) / 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()); }
|
||||
|
||||
uint32 GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
|
||||
SIZE_T GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
|
||||
|
||||
private:
|
||||
FVector Origin;
|
||||
|
@ -1135,7 +1139,7 @@ private:
|
|||
UBodySetup* BodySetup;
|
||||
EWidgetBlendMode BlendMode;
|
||||
EWidgetGeometryMode GeometryMode;
|
||||
float ArcAngle;
|
||||
double ArcAngle;
|
||||
bool bCreateSceneProxy;
|
||||
};
|
||||
|
||||
|
@ -1149,10 +1153,13 @@ FPrimitiveSceneProxy* UVRStereoWidgetComponent::CreateSceneProxy()
|
|||
|
||||
if (WidgetRenderer && GetSlateWindow() && GetSlateWindow()->GetContent() != SNullWidget::NullWidget)
|
||||
{
|
||||
RequestRenderUpdate();
|
||||
LastWidgetRenderTime = 0;
|
||||
if (ISlate3DRenderer* SlateRenderer = WidgetRenderer->GetSlateRenderer())
|
||||
{
|
||||
RequestRenderUpdate();
|
||||
LastWidgetRenderTime = 0;
|
||||
|
||||
return new FStereoWidget3DSceneProxy(this, *WidgetRenderer->GetSlateRenderer());
|
||||
return new FStereoWidget3DSceneProxy(this, *SlateRenderer);
|
||||
}
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
|
@ -1208,7 +1215,7 @@ FPrimitiveSceneProxy* UVRStereoWidgetComponent::CreateSceneProxy()
|
|||
return Result;
|
||||
}
|
||||
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:
|
||||
const FVector BoxExtents;
|
||||
|
|
|
@ -88,7 +88,7 @@ public:
|
|||
UPROPERTY()
|
||||
uint8 MoveActionFlags;
|
||||
UPROPERTY()
|
||||
TArray<UObject*> MoveActionObjectReferences;
|
||||
TArray<TObjectPtr<UObject>> MoveActionObjectReferences;
|
||||
UPROPERTY()
|
||||
EVRMoveActionVelocityRetention VelRetentionSetting;
|
||||
|
||||
|
@ -516,7 +516,7 @@ public:
|
|||
|
||||
// Moved these here to avoid having to duplicate tons of properties
|
||||
UPROPERTY(Transient)
|
||||
UPrimitiveComponent* ClientMovementBase;
|
||||
TObjectPtr<UPrimitiveComponent> ClientMovementBase;
|
||||
UPROPERTY(Transient)
|
||||
FName ClientBaseBoneName;
|
||||
|
||||
|
|
|
@ -809,7 +809,7 @@ public:
|
|||
}
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "GripMotionController")
|
||||
TArray<UPrimitiveComponent *> AdditionalLateUpdateComponents;
|
||||
TArray<TObjectPtr<UPrimitiveComponent>> AdditionalLateUpdateComponents;
|
||||
|
||||
// Movement Replication
|
||||
// Actor needs to be replicated for this to work
|
||||
|
|
|
@ -64,8 +64,11 @@ private:
|
|||
TMap<Chaos::FConstPhysicsObjectHandle, FReplicatedPhysicsTargetAsync> ObjectToTarget;
|
||||
TMap<Chaos::FConstPhysicsObjectHandle, FNetworkPhysicsSettingsAsync> ObjectToSettings;
|
||||
TArray<int32> ParticlesInResimIslands;
|
||||
TArray<Chaos::FParticleID> ReplicatedParticleIDs;
|
||||
|
||||
private:
|
||||
FReplicatedPhysicsTargetAsync* AddObjectToReplication(Chaos::FConstPhysicsObjectHandle PhysicsObject);
|
||||
void RemoveObjectFromReplication(Chaos::FConstPhysicsObjectHandle PhysicsObject);
|
||||
void UpdateAsyncTarget(const FPhysicsRepAsyncInputData& Input, Chaos::FPBDRigidsSolver* RigidsSolver);
|
||||
void UpdateRewindDataTarget(const FPhysicsRepAsyncInputData& Input);
|
||||
void CacheResimInteractions();
|
||||
|
@ -105,6 +108,7 @@ public:
|
|||
TArray<FReplicatedPhysicsTarget> ReplicatedTargetsQueueVR;
|
||||
FPhysicsReplicationAsyncVR* PhysicsReplicationAsyncVR;
|
||||
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)
|
||||
};
|
||||
|
|
|
@ -113,7 +113,7 @@ struct FAISightTargetVR
|
|||
static const FTargetId InvalidTargetId;
|
||||
|
||||
TWeakObjectPtr<AActor> Target;
|
||||
IAISightTargetInterface* SightTargetInterface;
|
||||
TWeakInterfacePtr<IAISightTargetInterface> WeakSightTargetInterface;
|
||||
FGenericTeamId TeamId;
|
||||
FTargetId TargetId;
|
||||
|
||||
|
@ -333,7 +333,7 @@ protected:
|
|||
FOnPendingVisibilityQueryProcessedDelegateVR OnPendingCanBeSeenQueryProcessedDelegate;
|
||||
FTraceDelegate OnPendingTraceQueryProcessedDelegate;
|
||||
|
||||
UE_MT_DECLARE_RW_ACCESS_DETECTOR(QueriesListAccessDetector);
|
||||
UE_MT_DECLARE_TS_RW_ACCESS_DETECTOR(QueriesListAccessDetector);
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
@ -28,17 +28,21 @@ public:
|
|||
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;
|
||||
|
||||
if (ConstraintInstance.ConstraintHandle->IsType(Chaos::EConstraintType::JointConstraintType))
|
||||
{
|
||||
|
||||
if (Chaos::FJointConstraint* Constraint = static_cast<Chaos::FJointConstraint*>(ConstraintInstance.ConstraintHandle.Constraint))
|
||||
{
|
||||
Constraint->SetLinearDriveForceMode(bUseForceConstraint ? Chaos::EJointForceMode::Force : Chaos::EJointForceMode::Acceleration);
|
||||
Constraint->SetAngularDriveForceMode(bUseForceConstraint ? Chaos::EJointForceMode::Force : Chaos::EJointForceMode::Acceleration);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
//#endif
|
||||
}
|
||||
|
|
|
@ -388,7 +388,7 @@ public:
|
|||
|
||||
/** */
|
||||
UPROPERTY(VisibleAnywhere, Instanced, NoClear, Category = "User Interface", meta = (ShowOnlyInnerProperties))
|
||||
UVRFullScreenUserWidget* ScreenUserWidget;
|
||||
TObjectPtr<UVRFullScreenUserWidget> ScreenUserWidget;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "FullScreenWidgetActor")
|
||||
UVRFullScreenUserWidget* GetPreviewWidgetComp();
|
||||
|
|
|
@ -175,7 +175,7 @@ protected:
|
|||
int numMessages = OutMessages.Num();
|
||||
if (numMessages > MaxStoredMessages)
|
||||
{
|
||||
OutMessages.RemoveAt(0, numMessages - MaxStoredMessages, true);
|
||||
OutMessages.RemoveAt(0, numMessages - MaxStoredMessages, EAllowShrinking::Yes);
|
||||
}
|
||||
if (OldNumMessages != numMessages)
|
||||
bIsDirty = true;
|
||||
|
|
|
@ -13,6 +13,40 @@
|
|||
#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.
|
||||
*/
|
||||
|
@ -24,6 +58,29 @@ class VREXPANSIONPLUGIN_API AVRWheeledVehicle : public AWheeledVehiclePawn
|
|||
|
||||
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")
|
||||
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!!
|
||||
//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")
|
||||
FBPVRComponentPosRep ReplicatedCameraTransform;
|
||||
|
|
|
@ -50,67 +50,7 @@ public:
|
|||
UPROPERTY(Transient)
|
||||
TObjectPtr<AActor> Owner;
|
||||
|
||||
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;
|
||||
}
|
||||
bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess);
|
||||
};
|
||||
|
||||
template<>
|
||||
|
@ -276,7 +216,7 @@ public:
|
|||
|
||||
/** BaseVR Character movement component belongs to */
|
||||
UPROPERTY(Transient, DuplicateTransient)
|
||||
AVRPlayerController* OwningVRPlayerController;
|
||||
TObjectPtr<AVRPlayerController> OwningVRPlayerController;
|
||||
|
||||
// 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
|
||||
|
|
|
@ -54,6 +54,7 @@ public:
|
|||
static const float CLIMB_SWEEP_EDGE_REJECT_DISTANCE;
|
||||
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 FVector GetActorFeetLocation() 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 "AbstractNavData.h"
|
||||
#include "Runtime/Launch/Resources/Version.h"
|
||||
|
||||
#include "VRPathFollowingComponent.generated.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogPathFollowingVR, Warning, All);
|
||||
|
@ -18,8 +19,17 @@ class VREXPANSIONPLUGIN_API UVRPathFollowingComponent : public UPathFollowingCom
|
|||
GENERATED_BODY()
|
||||
|
||||
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
|
||||
void SetMovementComponent(UNavMovementComponent* MoveComp) override;
|
||||
|
@ -28,29 +38,29 @@ public:
|
|||
// Have to override this to call the correct HasReachCurrentTarget
|
||||
void UpdatePathSegment() override;
|
||||
bool HasReachedCurrentTarget(const FVector& CurrentLocation) const;
|
||||
|
||||
*/
|
||||
// Had to override this to get the correct DebugReachTest
|
||||
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;
|
||||
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.
|
||||
/** notify about finished movement */
|
||||
//virtual void OnPathFinished(const FPathFollowingResult& Result) override;
|
||||
|
||||
/** pause path following
|
||||
// notify about finished movement
|
||||
virtual void OnPathFinished(const FPathFollowingResult& Result) override;
|
||||
*/
|
||||
/* pause path following
|
||||
* @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
|
||||
//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
|
||||
bool ShouldCheckPathOnResume() const override;
|
||||
|
||||
// Fine in 4.13, had to change feet based for both
|
||||
bool UpdateBlockDetection() override;
|
||||
bool UpdateBlockDetection() override;*/
|
||||
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"FileVersion": 3,
|
||||
"EngineAssociation": "5.4",
|
||||
"EngineAssociation": "5.5",
|
||||
"Category": "",
|
||||
"Description": "",
|
||||
"Modules": [
|
||||
|
|
Loading…
Reference in a new issue