|
| 1 | +### Key Concepts |
| 2 | +#### Slot Tracks |
| 3 | +```c++ |
| 4 | +class UAnimMontage : public UAnimCompositeBase |
| 5 | +{ |
| 6 | + // slot data, each slot contains anim track |
| 7 | + UPROPERTY() |
| 8 | + TArray<struct FSlotAnimationTrack> SlotAnimTracks; |
| 9 | +}; |
| 10 | + |
| 11 | +/** |
| 12 | + * Each slot data referenced by Animation Slot |
| 13 | + * contains slot name, and animation data |
| 14 | + */ |
| 15 | +USTRUCT() |
| 16 | +struct FSlotAnimationTrack |
| 17 | +{ |
| 18 | + GENERATED_USTRUCT_BODY() |
| 19 | + |
| 20 | + UPROPERTY(EditAnywhere, Category=Slot) |
| 21 | + FName SlotName; |
| 22 | + |
| 23 | + UPROPERTY(EditAnywhere, Category=Slot) |
| 24 | + FAnimTrack AnimTrack; |
| 25 | + |
| 26 | + ENGINE_API FSlotAnimationTrack(); |
| 27 | +}; |
| 28 | +``` |
| 29 | +一个 montage 由多个 slot track 组成,每个 slot track 的 `SlotName` 与动画蓝图中的 slot 节点的 slot name 相对应,并且这些 slot 必须属于同一个 slot group。每个 slot track(表示为 `FAnimTrack` 结构体)由多个基本的 animation asset 拼接而成,拼接的 animation asset 可以只是原本的 animation asset 的一部分(由 `FAnimSegment` 的 `AnimStartTime` 和 `AnimEndTime` 控制) |
| 30 | +```c++ |
| 31 | +/** This is list of anim segments for this track |
| 32 | + * For now this is only one TArray, but in the future |
| 33 | + * we should define more transition/blending behaviors |
| 34 | + **/ |
| 35 | +USTRUCT() |
| 36 | +struct FAnimTrack |
| 37 | +{ |
| 38 | + UPROPERTY(EditAnywhere, Category=AnimTrack, EditFixedSize) |
| 39 | + TArray<FAnimSegment> AnimSegments; |
| 40 | +}; |
| 41 | + |
| 42 | +/** this is anim segment that defines what animation and how **/ |
| 43 | +USTRUCT() |
| 44 | +struct FAnimSegment |
| 45 | +{ |
| 46 | + UPROPERTY(EditAnywhere, Category=AnimSegment, meta=(DisplayName = "Animation Reference")) |
| 47 | + TObjectPtr<UAnimSequenceBase> AnimReference; |
| 48 | + |
| 49 | + /** Start Pos within this AnimCompositeBase */ |
| 50 | + UPROPERTY(VisibleAnywhere, Category=AnimSegment, meta=(DisplayName = "Starting Position")) |
| 51 | + float StartPos; |
| 52 | + |
| 53 | + /** Time to start playing AnimSequence at. */ |
| 54 | + UPROPERTY(EditAnywhere, Category=AnimSegment, meta=(DisplayName = "Start Time")) |
| 55 | + float AnimStartTime; |
| 56 | + |
| 57 | + /** Time to end playing the AnimSequence at. */ |
| 58 | + UPROPERTY(EditAnywhere, Category=AnimSegment, meta=(DisplayName = "End Time")) |
| 59 | + float AnimEndTime; |
| 60 | + |
| 61 | + /** Playback speed of this animation. If you'd like to reverse, set -1*/ |
| 62 | + UPROPERTY(EditAnywhere, Category=AnimSegment, meta=(DisplayName = "Play Rate")) |
| 63 | + float AnimPlayRate; |
| 64 | + |
| 65 | + UPROPERTY(EditAnywhere, Category=AnimSegment, meta=(DisplayName = "Loop Count")) |
| 66 | + int32 LoopingCount; |
| 67 | +}; |
| 68 | +``` |
| 69 | +#### Slot and Slot Group |
| 70 | +montage 能使用的所有的 slot 和 slot group 保存在 `USkeleton` 的 `SlotGroups` 中,`SlotToGroupNameMap` 用于快速查找,在 skeleton 反序列化时根据 `SlotGroups` 构建的 |
| 71 | +```c++ |
| 72 | + // serialized slot groups and slot names. |
| 73 | + UPROPERTY() |
| 74 | + TArray<FAnimSlotGroup> SlotGroups; |
| 75 | + |
| 76 | + /** SlotName to GroupName TMap, only at runtime, not serialized. **/ |
| 77 | + TMap<FName, FName> SlotToGroupNameMap; |
| 78 | +``` |
| 79 | +虽然 [Animation Slots](https://dev.epicgames.com/documentation/en-us/unreal-engine/animation-slots-in-unreal-engine) 文档中说同一个 group 中只能有一个 montage 处于播放状态,但实际上是可以有多个的 |
| 80 | +```c++ |
| 81 | + /** Plays an animation montage. Returns the length of the animation montage in seconds. Returns 0.f if failed to play. */ |
| 82 | + UFUNCTION(BlueprintCallable, Category = "Animation|Montage") |
| 83 | + ENGINE_API float Montage_Play(UAnimMontage* MontageToPlay, float InPlayRate = 1.f, EMontagePlayReturnType ReturnValueType = EMontagePlayReturnType::MontageLength, float InTimeToStartMontageAt=0.f, bool bStopAllMontages = true); |
| 84 | +``` |
| 85 | +其中参数 `bStopAllMontages` 默认值为 true,表示停止同一个 group 的其它 montage。但如果调用该函数时传入的 `bStopAllMontages` 为 false,则同一个 group,甚至同一个 slot 中,可以有多个 montage 同时播放 |
| 86 | +
|
| 87 | +所有权重非零的 montage 都记录在 `UAnimInstance` 的 `MontageInstances` 字段,虽然它注释中也说要求 group 中至多一个 montage 在播放 |
| 88 | +```c++ |
| 89 | + /** AnimMontage instances that are running currently |
| 90 | + * - only one is primarily active per group, and the other ones are blending out |
| 91 | + */ |
| 92 | + TArray<struct FAnimMontageInstance*> MontageInstances; |
| 93 | +``` |
| 94 | +如果希望 group 中只有一个 montage 在播放,同时又想多个激活 group 中的多个 slot,只需要给这个 montage 添加多个 slot track 即可 |
| 95 | + |
| 96 | +具体 graph node 的 slot 是如何进行混合的,见 Animation Blending in Unreal 中的说明 |
| 97 | +#### Section |
| 98 | +整个播放进度条可以划分为若干 section,每个 section 的名称,开始时间,连接的下一个 section 等信息存放在 `CompositeSections` 中 |
| 99 | +```c++ |
| 100 | +class UAnimMontage : public UAnimCompositeBase |
| 101 | +{ |
| 102 | + // composite section. |
| 103 | + UPROPERTY() |
| 104 | + TArray<FCompositeSection> CompositeSections; |
| 105 | +}; |
| 106 | + |
| 107 | +/** |
| 108 | + * Section data for each track. Reference of data will be stored in the child class for the way they want |
| 109 | + * AnimComposite vs AnimMontage have different requirement for the actual data reference |
| 110 | + * This only contains composite section information. (vertical sequences) |
| 111 | + */ |
| 112 | +USTRUCT() |
| 113 | +struct FCompositeSection : public FAnimLinkableElement |
| 114 | +{ |
| 115 | + /** Section Name */ |
| 116 | + UPROPERTY(EditAnywhere, Category=Section) |
| 117 | + FName SectionName; |
| 118 | + |
| 119 | + /** Should this animation loop. */ |
| 120 | + UPROPERTY(VisibleAnywhere, Category=Section) |
| 121 | + FName NextSectionName; |
| 122 | +}; |
| 123 | +``` |
0 commit comments