一不小心就暴露了自己的知识水平
在没有深入了解蒙太奇这方面的原理前,一直都以为播放一个蒙太奇时会将其所占据的所有slot上正在播放的其他蒙太奇给终止掉。
可以用一个及其简单的例子来证明这个是错误的:
如图AnimGraph, SlotNode 直接连接输出节点。
接着,在EventGraph中的初始化函数中调用Montage_Play接口,任意选取一个蒙太奇,将PlayRate调小方便观看,并取消勾选 StopAllMontages
选项。
此时点击编译,会发现十分正常的播放了这个蒙太奇。
继续添加类似节点,并选取一个与先前的蒙太奇差异较大的资源,再次点击编译。
你会发现两个蒙太奇被混合到了一起。
具体代码可以参考 FAnimInstanceProxy::SlotEvaluatePose
函数:
// 遍历所有执行中的蒙太奇数据 将所有包含指定的slot的蒙太奇进行收集 for (const FMontageEvaluationState& EvalState : MontageEvaluationData) { const UAnimMontage* const Montage = EvalState.Montage.Get(); if (Montage->IsValidSlot(SlotNodeName)) { if (AdditiveAnimType == AAT_None) { NonAdditivePoses.Add(FSlotEvaluationPose(MoveTemp(NewPose))); } else { AdditivePoses.Add(FSlotEvaluationPose(MoveTemp(NewPose))); } } } // ... // 获取所有非additive动画的Pose以及权重 int32 const NumPoses = NonAdditivePoses.Num() + ((SourceWeight > ZERO_ANIMWEIGHT_THRESH) ? 1 : 0); BlendingPoses.AddUninitialized(NumPoses); BlendWeights.AddUninitialized(NumPoses); for (int32 Index = 0; Index < NonAdditivePoses.Num(); Index++) { BlendingPoses[Index] = &NonAdditivePoses[Index].Pose; BlendWeights[Index] = NonAdditivePoses[Index].Weight; } // 如果有Source节点(即SlotNode连接的输入节点) // 则也记录其Pose以及权重 if (SourceWeight > ZERO_ANIMWEIGHT_THRESH) { int32 const SourceIndex = BlendWeights.Num() - 1; BlendingPoses[SourceIndex] = &SourcePose; BlendWeights[SourceIndex] = SourceWeight; } // 对收集来的数据进行混合 FAnimationRuntime::BlendPosesTogetherIndirect(BlendingPoses, BlendingCurves, BlendingAttributes, BlendWeights, OutBlendedAnimationPoseData);
之前使用 Montage_Play 函数播放蒙太奇时,有一个 StopAllMontage
参数,在之前我对这个参数存在了一个非常能自圆其说的误解,总结如下:
StopAllMontage
是将除了该蒙太奇以外的所有蒙太奇终止掉。事实上,该参数为true时,只会终止蒙太奇占用的第一个Track的Slot所在的Group内的其他蒙太奇。
可以参考 UAnimInstance::Montage_Play
:
if (bStopAllMontages) { FName NewMontageGroupName = MontageToPlay->GetGroupName(); StopAllMontagesByGroupName(NewMontageGroupName, MontageToPlay->BlendIn); }
但是这里有一点比较违反直觉(虽然这参数叫StopAllMontages就已经很违反直觉了),因为蒙太奇其实可以有多个slot,为什么这里不将所有的slot的group给终止掉呢?
好吧,原来是生成蒙太奇资产的时候就规定了,所有track的slot必须在同一个group下。
仔细一想其实也是合理的,因为既然是同一个蒙太奇,里面不同的track理当是同一种类型的动画才对。