当前位置:网站首页>UE source code analysis: uccharactermovementcomponent - rootmotion
UE source code analysis: uccharactermovementcomponent - rootmotion
2022-07-03 19:15:00 【JK Chen】
brief introduction
RootMotion In two parts : From animation RootMotion And customization RootMotionSource
UCharacterMovementComponent::ApplyRootMotionSource
original edition CMC Mutually exclusive use both
RootMotion By changing Velocity Act on CMC, The main code is UCharacterMovementComponent::PerformMovement
Inside
Data flow
Data on ,AnimInstance Inside FAnimMontageInstance Relevant data are :
/** AnimMontage instances that are running currently * - only one is primarily active per group, and the other ones are blending out */
TArray<struct FAnimMontageInstance*> MontageInstances;
/** Map between Active Montages and their FAnimMontageInstance */
TMap<class UAnimMontage*, struct FAnimMontageInstance*> ActiveMontagesMap;
/** Active Root Motion Montage Instance, if any. */
struct FAnimMontageInstance* RootMotionMontageInstance;
adopt RootMotionMontageInstance Get current RootMotion Corresponding Montage
float UAnimInstance::Montage_Play(UAnimMontage* MontageToPlay, float InPlayRate/*= 1.f*/, EMontagePlayReturnType ReturnValueType, float InTimeToStartMontageAt, bool bStopAllMontages /*= true*/)
if (MontageToPlay->HasRootMotion())
RootMotionMontageInstance = NewInstance;
FAnimMontageInstance * ACharacter::GetRootMotionAnimMontageInstance() const
return (Mesh && Mesh->GetAnimInstance()) ? Mesh->GetAnimInstance()->GetRootMotionMontageInstance() : nullptr;
AnimInstance Deal with FRootMotionMovementParams
Update process : bones - Animation blueprint - Montage - RootMotion
void USkeletalMeshComponent::TickAnimation(float DeltaTime, bool bNeedsValidRootMotion)
void UAnimInstance::UpdateAnimation(float DeltaSeconds, bool bNeedsValidRootMotion, EUpdateAnimationFlag UpdateFlag)
void UAnimInstance::UpdateMontage(float DeltaSeconds)
void UAnimInstance::Montage_Advance(float DeltaSeconds)
void FAnimMontageInstance::Advance(float DeltaTime, struct FRootMotionMovementParams* OutRootMotionParams, bool bBlendRootMotion)
// take Mesh Of RootMotion The accumulation of (FTransform Multiply) To RootMotionParams
OutRootMotionParams->Accumulate(RootMotion);
Save to :
// Root motion read from proxy (where it is calculated) and stored here to avoid potential stalls by calling GetProxyOnGameThread
FRootMotionMovementParams UAnimInstance::ExtractedRootMotion;
CMC Use FRootMotionMovementParams
FRootMotionMovementParams USkeletalMeshComponent::ConsumeRootMotion()
FRootMotionMovementParams USkeletalMeshComponent::ConsumeRootMotion_Internal(float InAlpha)
FRootMotionMovementParams UAnimInstance::ConsumeExtractedRootMotion(float Alpha)
ExtractedRootMotion
Move inside the component FRootMotionMovementParams
/** Root Motion movement params. Holds result of anim montage root motion during PerformMovement(), and is overridden * during autonomous move playback to force historical root motion for MoveAutonomous() calls */
UPROPERTY(Transient)
FRootMotionMovementParams RootMotionParams;
This deposit is procedural AnimRootMotion, Whether there is AnimRootMotion Also use this to judge , from ExtractedRootMotion Cumulative
bool UCharacterMovementComponent::HasAnimRootMotion() const
return RootMotionParams.bHasRootMotion;
Applied to the CMC The process of
void UCharacterMovementComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
void UCharacterMovementComponent::PerformMovement(float DeltaSeconds)
void UCharacterMovementComponent::TickCharacterPose(float DeltaTime)
// to update ExtractedRootMotion
void USkeletalMeshComponent::TickPose(float DeltaTime, bool bNeedsValidRootMotion)
void USkeletalMeshComponent::TickAnimation(float DeltaTime, bool bNeedsValidRootMotion)
// obtain ExtractedRootMotion
FRootMotionMovementParams RootMotion = CharacterMesh->ConsumeRootMotion();
if (RootMotion.bHasRootMotion)
{
RootMotion.ScaleRootMotionTranslation(CharacterOwner->GetAnimRootMotionTranslationScale());
// Accumulate inside the mobile component
RootMotionParams.Accumulate(RootMotion);
}
// Handle RootMotionSource
CurrentRootMotion.PrepareRootMotion(DeltaSeconds, *CharacterOwner, *this, true);
// Use Override RootMotionSource perhaps RootMotionParams Update speed
if( CurrentRootMotion.HasOverrideVelocity() || HasAnimRootMotion() )
// Use RootMotionParams
if( HasAnimRootMotion() )
// direct override by AnimRootMotion Of Velocity
AnimRootMotionVelocity = CalcAnimRootMotionVelocity(RootMotionParams.GetRootMotionTransform().GetTranslation(), DeltaSeconds, Velocity);
Velocity = ConstrainAnimRootMotionVelocity(AnimRootMotionVelocity, Velocity);
// Use Override RootMotionSource
else
CurrentRootMotion.AccumulateOverrideRootMotionVelocity(DeltaSeconds, *CharacterOwner, *this, NewVelocity);
Velocity = NewVelocity;
// Update location ( See the analysis below )
void UCharacterMovementComponent::StartNewPhysics(float deltaTime, int32 Iterations)
void UCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iterations)
// Update rotation
if( HasAnimRootMotion() )
MoveUpdatedComponent(FVector::ZeroVector, NewActorRotationQuat, true);
else if (CurrentRootMotion.HasActiveRootMotionSources())
MoveUpdatedComponent(FVector::ZeroVector, NewActorRotationQuat, true);
If you go RootMotionSource Words , stay PerformMovement It did Override,PhysWalking Do inside Override and Additive, The one outside here is redundant
void UCharacterMovementComponent::PhysWalking(float deltaTime, int32 Iterations)
while ( (remainingTime >= MIN_TICK_TIME) && (Iterations < MaxSimulationIterations) && CharacterOwner && (CharacterOwner->Controller || bRunPhysicsWithNoController || HasAnimRootMotion() || CurrentRootMotion.HasOverrideVelocity() || (CharacterOwner->GetLocalRole() == ROLE_SimulatedProxy)) )
RestorePreAdditiveRootMotionVelocity();
void UCharacterMovementComponent::ApplyRootMotionToVelocity(float deltaTime)
// application AnimRootMotion
if( HasAnimRootMotion() && deltaTime > 0.f )
Velocity = ConstrainAnimRootMotionVelocity(AnimRootMotionVelocity, Velocity);
return;
// application Override RootMotionSource
if( CurrentRootMotion.HasOverrideVelocity() )
CurrentRootMotion.AccumulateOverrideRootMotionVelocity(deltaTime, *CharacterOwner, *this, Velocity);
// application Additive RootMotionSource
if( CurrentRootMotion.HasAdditiveVelocity() )
CurrentRootMotion.AccumulateAdditiveRootMotionVelocity(deltaTime, *CharacterOwner, *this, Velocity);
// Movement and other subsequent processing
MoveAlongFloor(MoveVelocity, timeTick, &StepDownResult);
Network synchronization
From Montage and RootMotionSource Two parts
The first part is due to AnimInstance On the client side , So naturally, it is synchronous
The second part ,ApplyRootMotionSource Will be added to CurrentRootMotion(FRootMotionSourceGroup) Of PendingAddRootMotionSources Inside
CMC Of PerformMovement In the use of RootMotion We'll call FRootMotionSourceGroup::PrepareRootMotion,RootMotionSources.Append(PendingAddRootMotionSources);
// Sync CurrentRootMotion
void ACharacter::PreReplication( IRepChangedPropertyTracker & ChangedPropertyTracker )
RepRootMotion.AuthoritativeRootMotion = CharacterMovement->CurrentRootMotion;
UPROPERTY(ReplicatedUsing=OnRep_RootMotion)
struct FRepRootMotionMontage ACharacter::RepRootMotion;
// The analog end uses the synchronized RepRootMotion
void ACharacter::OnRep_RootMotion()
if (GetLocalRole() == ROLE_SimulatedProxy)
RootMotionRepMoves.AddZeroed(1);
// Analog end at SimulatedTick Will use RootMotionRepMoves Realization RootMotion
FSimulatedRootMotionReplicatedMove& NewMove = RootMotionRepMoves.Last();
NewMove.RootMotion = RepRootMotion;
correct
int32 UNetDriver::ServerReplicateActors(float DeltaSeconds)
PlayerController->SendClientAdjustment()
if (RemotePawn && (RemotePawn->GetRemoteRole() == ROLE_AutonomousProxy) && !IsNetMode(NM_Client))
{
INetworkPredictionInterface* NetworkPredictionInterface = Cast<INetworkPredictionInterface>(RemotePawn->GetMovementComponent());
if (NetworkPredictionInterface)
{
// Main control end
NetworkPredictionInterface->SendClientAdjustment();
}
}
void UCharacterMovementComponent::SendClientAdjustment()
if (CurrentRootMotion.HasActiveRootMotionSources())
ClientAdjustRootMotionSourcePosition(...)
else if (bIsPlayingNetworkedRootMotionMontage)
ClientAdjustRootMotionPosition(...)
边栏推荐
- Valentine's Day - make an exclusive digital collection for your lover
- How can I avoid "div/0!" Errors in Google Docs spreadsheet- How do I avoid the '#DIV/0!' error in Google docs spreadsheet?
- 变化是永恒的主题
- 【光学】基于matlab涡旋光产生【含Matlab源码 1927期】
- The installation path cannot be selected when installing MySQL 8.0.23
- KINGS
- The more you talk, the more your stupidity will be exposed.
- Using the visualization results, click to appear the corresponding sentence
- Analysis of dart JSON encoder and decoder
- [optics] vortex generation based on MATLAB [including Matlab source code 1927]
猜你喜欢
Why should the gradient be manually cleared before back propagation in pytorch?
[proteus simulation] a simple encrypted electronic password lock designed with 24C04 and 1602LCD
我们做了一个智能零售结算平台
SQL custom collation
If the warehouse management communication is not in place, what problems will occur?
[disease identification] machine vision lung cancer detection system based on Matlab GUI [including Matlab source code 1922]
How to build an efficient information warehouse
Record: MySQL changes the time zone
Sentinel source code analysis part I sentinel overview
[leetcode weekly race] game 300 - 6110 Number of incremental paths in the grid graph - difficult
随机推荐
EGO Planner代码解析bspline_optimizer部分(2)
达梦数据库的物理备份和还原简解
We have built an intelligent retail settlement platform
Dart JSON编码器和解码器剖析
Simple solution of physical backup and restore of Damon database
Which do MySQL and Oracle learn?
Today I am filled with emotion
Pan for in-depth understanding of the attention mechanism in CV
Integrated easy to pay secondary domain name distribution system
Failed to start component [StandardEngine[Catalina]. StandardHost[localhost]. StandardContext
Go home early today
Flutter网络和数据存储框架搭建 -b1
Scrape crawler framework
PyTorch中在反向传播前为什么要手动将梯度清零?
During MySQL installation, the download interface is empty, and the components to be downloaded are not displayed. MySQL installer 8.0.28.0 download interface is empty solution
These problems should be paid attention to in the production of enterprise promotional videos
[optics] vortex generation based on MATLAB [including Matlab source code 1927]
Zhengda futures news: soaring oil prices may continue to push up global inflation
变化是永恒的主题
2020 intermediate financial management (escort class)