【UE4】Animation notification

AnimNotifyThis article summarizes the source code analysis and problem summary of animation notifications (animation notification status AnimNotifyState)    in UE4 .

1. Introduction to animated notifications

   Animation notifications are notifications that are mainly configured on animation ( Animation) or animation montage ( ) in UE4 . The notification is triggered by the running of the animation. AnimMontageThere are two types of notifications:

  1. AnimNotify(animated notification) – no duration; only Notifymethod; see detailsAnimNotify.h
  2. AnimNotifyState(Animation notification status) – has a duration ( TotalDuration); has NotifyBegin, NotifyTick, NotifyEndmethod; see for detailsAnimNotifyState.h

  For AnimNotifyState, the official description says:

  • It is guaranteed to start from Notify Begin Event
  • It is guaranteed to end from Notify End Event
  • It is guaranteed that the Notify Tick is between the Notify Begin and Notify End events.
  • The order of Anim Notifies (normal or state) cannot be guaranteed . If two AnimNotifyStates are connected end to end, there is no guarantee that the End of the previous Notify is before the Begin of the next one. Only separate operations that are not related to other Notify should be performed here. original:

The order between different Anim Notifies (normal or state) is not guaranteed.
If you put two Anim Notify States next to each other, the first one is not guaranteed to end before the next one starts.
Only use this for individual actions which do not rely on other Notifies.

  That is, the two AnimNotifyStates, A and B, cannot guarantee that the execution order is:

A.Begin --> A.End --> B.Begin --> B.End

  Instead it might be:

A.Begin --> B.Begin --> A.End --> B.End

Additionally, it’s worth noting:

  1. Animation notifications will be executed by default on the DedicateServer, the main control terminal, and the simulation segment. If you don't want to execute it on DS, you can uncheck the option below in the options.
    Insert image description here

  2. For notifications on the same Montage or Animation, the pointer is the same , so if data is stored in the notification, and two identical roles release the same Montage at the same time, two notifications will modify the same piece of data;

  3. Multiple notifications of the same type on the same Montage have different pointers. What comes out of GetName() is xxx_C_1, xxx_C_2 like this

2. Triggering of animated notifications

  The triggering of the above methods of animation notification is mainly triggered UAnimInstance::TriggerAnimNotifiesfrom (there are others that will be discussed later).

2.1 TriggerAnimNotifies source code analysis

  In Tick, the ( type) AnimInstancein will add the animation notifications (AnimNotify, AnimNotifyState) of this frame , and then execute all the animation notifications of this frame in TriggerAnimNotifies. The execution order is:NotifyQueueAnimNotifiesFAnimNotifyQueue

  1. all AnimNotifyofNotify
  2. All the previous ones are still there, but this frame is no longer AnimNotifyStatethereNotifyEnd
  3. The previous frame is not there, it is newly added in this frame AnimNotifyState.NotifyBegin
  4. AnimNotifyStateAll of this frame NotifyTick(that is, the same frame of Begin will Tick)

  For AnimNotify, there is only Notify, so it is relatively simple and will not be discussed. Next, we AnimNotifyStatewill focus on the analysis:
   AnimNotifyStatethe trigger core is four arrays:

  1. ActiveAnimNotifyState: Record the previous frame in Active AnimNotifyState(referred to as Act)
  2. NotifyQueue.AnimNotifies: Record all Notify on this frame Montage (including Notify and NotifyState)
  3. NewActiveAnimNotifyState(Partial): Calculate which are the new NotifyStates (NewAct for short) of this frame through 1 and 2
  4. NotifyStateBeginEvent(Partial): Only used to trigger new NotifyStateNotifyBegin
2.2 TriggerAnimNotifies complete process analysis
1. Create NewActiveAnimNotifyState
// Array that will replace the 'ActiveAnimNotifyState' at the end of this function. 
TArray<FAnimNotifyEvent> NewActiveAnimNotifyState; 
NewActiveAnimNotifyState.Reserve(NotifyQueue.AnimNotifies.Num());
2. The most critical step

  Delete ActiveAnimNotifyStatethe ones that are still there in this frame, and the remaining ones are those that were in the previous frame and are not in this frame, and are used for subsequent triggers NotifyEnd;
  put the ones that are not in the previous frame and are in this frame, NotifyStateBeginEventand are used in the future. Trigger NotifyBegin;
  trigger everything AnimNotify;

// AnimNotifyState freshly added that need their 'NotifyBegin' event called. 
TArray<const FAnimNotifyEvent *> NotifyStateBeginEvent; 
 
for (int32 Index=0; Index<NotifyQueue.AnimNotifies.Num(); Index++) 
{
    
     
    if(const FAnimNotifyEvent* AnimNotifyEvent = NotifyQueue.AnimNotifies[Index].GetNotify()) 
    {
    
    
        // AnimNotifyState 
        if (AnimNotifyEvent->NotifyStateClass) 
        {
    
     
            if (!ActiveAnimNotifyState.RemoveSingleSwap(*AnimNotifyEvent, false)) 
            {
    
    
                // Queue up calls to 'NotifyBegin', so they happen after 'NotifyEnd'. 
                NotifyStateBeginEvent.Add(AnimNotifyEvent);
            }
            NewActiveAnimNotifyState.Add(*AnimNotifyEvent);
            continue;
        }
 
        // Trigger non 'state' AnimNotifies 
        TriggerSingleAnimNotify(AnimNotifyEvent);
    }
}
3. Trigger all NotifyEnds in Act
// Send end notification to AnimNotifyState not active anymore. 
for (int32 Index = 0; Index < ActiveAnimNotifyState.Num(); ++Index) 
{
    
     
    const FAnimNotifyEvent& AnimNotifyEvent = ActiveAnimNotifyState[Index]; 
    if (AnimNotifyEvent.NotifyStateClass && ShouldTriggerAnimNotifyState(AnimNotifyEvent.NotifyStateClass)) 
    {
    
     
        TRACE_ANIM_NOTIFY(this, AnimNotifyEvent, End); 
        AnimNotifyEvent.NotifyStateClass->NotifyEnd(
        	SkelMeshComp, 
        	Cast<UAnimSequenceBase>(AnimNotifyEvent.NotifyStateClass->GetOuter())); 
    } 
    // blabla ActiveAnimNotifyState 是否已经失效检查
}
4. Trigger all NotifyBegin in NotifyStateBeginEvent
// Call 'NotifyBegin' event on freshly added AnimNotifyState. 
for (const FAnimNotifyEvent* AnimNotifyEvent : NotifyStateBeginEvent) 
{
    
     
    if (ShouldTriggerAnimNotifyState(AnimNotifyEvent->NotifyStateClass)) 
    {
    
     
        TRACE_ANIM_NOTIFY(this, *AnimNotifyEvent, Begin); 
        AnimNotifyEvent->NotifyStateClass->NotifyBegin(
        	SkelMeshComp, 
        	Cast<UAnimSequenceBase>(AnimNotifyEvent->NotifyStateClass->GetOuter()), 
        	AnimNotifyEvent->GetDuration()); 
    } 
}
5. MoveTemp
// Switch our arrays. 
ActiveAnimNotifyState = MoveTemp(NewActiveAnimNotifyState);

  Give NewAct to Act, because Act is a member variable and NewAct is a local variable.

6. Trigger all NotifyTicks in the Act
// Tick currently active AnimNotifyState 
for(const FAnimNotifyEvent& AnimNotifyEvent : ActiveAnimNotifyState) 
{
    
     
    if (ShouldTriggerAnimNotifyState(AnimNotifyEvent.NotifyStateClass)) 
    {
    
     
        TRACE_ANIM_NOTIFY(this, AnimNotifyEvent, Tick); 
        AnimNotifyEvent.NotifyStateClass->NotifyTick(
        	SkelMeshComp, 
        	Cast<UAnimSequenceBase>(AnimNotifyEvent.NotifyStateClass->GetOuter()), 
        	DeltaSeconds); 
    }
}

Additionally, it’s worth noting:

  1. Since NotifyEndthe method of judging whether to trigger is to judge whether the previous frame of A notification is still there and this frame is not there , it will not be triggered when it looks like the last frame of the notification. NotifyEndThat is, two notifications connected end to end will definitely The following ones Begin first, and the ones in front of the next frame are Ended. They don't even need to be connected end to end, but the beginning and the end are in the same frame (as shown below). Similarly, the following ones Begin first, and the ones in front of the next frame are Ended.
    Insert image description here

3. Summary of issues with animated notifications

  See details

Guess you like

Origin blog.csdn.net/Bob__yuan/article/details/115520679