情報共有:AnimationのFrameSkipをSkeletalMeshから調整する。

お世話になっております。

この間のCEDEC2018で講演されていた【UE4で多数のキャラクターを生かすためのテクニック】、【UE4アニメーションシステム総おさらい】を元にSkeletalMeshComponentからAnimationのFrameSkipを調整できるように対応してみました。



まず、概要から。

Engine.hにある、FAnimUpdateRateParametersがUpdateRate関連の調整パラメーターになります。

これは

FAnimUpdateRateParameters* GetUpdateRateParameters(USkinnedMeshComponent* SkinnedComponent)
内で実体が作成されており、

void USkinnedMeshComponent::OnRegister()、void USkinnedMeshComponent::RefreshUpdateRateParams()から呼び出されて割り当てが行われています。

BluePrintからこの割り当てられたインスタンスを使っても良いのですが、今回自分はインスタンス作成時に、調整したパラメーターを受け渡す形に致しました。

対応方法は以下になります。



//--------------Engine.h------//

最大スキップが4フレームを超えるとカラーが足りないので拡張。

必須な対応ではありません。

FColor GetUpdateRateDebugColor() const

{

if (OptimizeMode == TrailMode)

{

switch (UpdateRate)

{

case 1: return FColor::Red;

case 2: return FColor::Green;

case 3: return FColor::Blue;

//=====yuu_kajii@winter-crown-works.com=======//

#if 1

case 4: return FColor::Cyan;

case 5: return FColor::Magenta;

case 6: return FColor::Purple;

case 7: return FColor::Turquoise;

case 8: return FColor::Silver;

case 9: return FColor::Emerald;

#else

#endif

//======================================//

}

return FColor::Black;

}

else

{

if (bSkipUpdate)

{

return FColor::Yellow;

}

return FColor::Green;

}

}



//--------------------------------//

//-------SkinnedMeshComponent.h----//

デバッグカラーを増やしたのでコメントの調整。

FAnimUpdateRateParametersから欲しいパラメーターを移植。

// Update Rate

/** if TRUE, Owner will determine how often animation will be updated and evaluated. See AnimUpdateRateTick()

* This allows to skip frames for performance. (For example based on visibility and size on screen). /

UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadWrite, Category=Optimization)

uint8 bEnableUpdateRateOptimizations:1;



//============ yuu_kajii@winter-crown-works.com =========================//

#if 1

/
* Enable on screen debugging of update rate optimization.

* Red = Skipping 0 frames, Green = skipping 1 frame, Blue = skipping 2 Cyan = skipping 3

Magenta = skipping 4 Purple = skipping 5 Turquoise = skipping 6 Silver = skipping 7

Emerald = skipping 8

frames, black = skipping more than 9 frames.

* @anonymous_user_5851a2121: turn this into a console command. /

UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadWrite, Category = Optimization)

uint8 bDisplayDebugUpdateRateOptimizations : 1;

#else

/
* Enable on screen debugging of update rate optimization.

* Red = Skipping 0 frames, Green = skipping 1 frame, Blue = skipping 2 frames, black = skipping more than 2 frames.
* @anonymous_user_5851a2121: turn this into a console command. /

UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadWrite, Category = Optimization)

uint8 bDisplayDebugUpdateRateOptimizations : 1;

#endif

//=========================================================================//



//============ yuu_kajii@winter-crown-works.com =========================//

#if 1

/
* Array of MaxDistanceFactor to use for AnimUpdateRate when mesh is visible (rendered).

* MaxDistanceFactor is size on screen, as used by LODs

* Example:

* BaseVisibleDistanceFactorThesholds.Add(0.4f)

* BaseVisibleDistanceFactorThesholds.Add(0.2f)

* means:

* 0 frame skip, MaxDistanceFactor > 0.4f

* 1 frame skip, MaxDistanceFactor > 0.2f

* 2 frame skip, MaxDistanceFactor > 0.0f

/

UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadOnly, Category = Optimization)

TArray BaseVisibleDistanceFactorThesholds;



/
* When skipping a frame, should it be interpolated or frozen? /

UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadOnly, Category = Optimization)

uint8 bInterpolateSkippedFrames : 1;



/
* Rate of animation evaluation when non rendered (off screen and dedicated servers).

* a value of 4 means evaluated 1 frame, then 3 frames skipped /

UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadOnly, Category = Optimization)

int32 BaseNonRenderedUpdateRate;



/
* Max Evaluation Rate allowed for interpolation to be enabled. Beyond, interpolation will be turned off. /

UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadOnly, Category = Optimization)

int32 MaxEvalRateForInterpolation;



UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadOnly, Category = Optimization)

EUpdateRateShiftBucket ShiftBucket;



#endif

//============ ================================ =========================//

//------------------------------------------//

//-------SkinnedMeshComponent.cpp----//

ここで実体生成時にパラメーターを受け渡し。

FAnimUpdateRateParameters
GetUpdateRateParameters(USkinnedMeshComponent* SkinnedComponent)

{

if (!SkinnedComponent)

{

return NULL;

}

UObject* TrackerIndex = GetMapIndexForComponent(SkinnedComponent);



FAnimUpdateRateParametersTracker** ExistingTrackerPtr = ActorToUpdateRateParams.Find(TrackerIndex);

if (!ExistingTrackerPtr)

{

ExistingTrackerPtr = &ActorToUpdateRateParams.Add(TrackerIndex);

(ExistingTrackerPtr) = new FAnimUpdateRateParametersTracker();

//============ yuu_kajii@winter-crown-works.com =========================//

#if 1

if (ExistingTrackerPtr != nullptr) {

FAnimUpdateRateParametersTracker
pExistingTracker = ExistingTrackerPtr;

FAnimUpdateRateParameters
pUpdateRateParams = &pExistingTracker-
>UpdateRateParameters;



pUpdateRateParams->BaseVisibleDistanceFactorThesholds = SkinnedComponent->BaseVisibleDistanceFactorThesholds;

pUpdateRateParams->bInterpolateSkippedFrames = SkinnedComponent->bInterpolateSkippedFrames;

pUpdateRateParams->BaseNonRenderedUpdateRate = SkinnedComponent->BaseNonRenderedUpdateRate;

pUpdateRateParams->MaxEvalRateForInterpolation = SkinnedComponent->MaxEvalRateForInterpolation;

pUpdateRateParams->ShiftBucket = SkinnedComponent->ShiftBucket;

}

#endif

//=========================================================================//



}



check(ExistingTrackerPtr);

FAnimUpdateRateParametersTracker* ExistingTracker = ExistingTrackerPtr;

check(ExistingTracker);

checkSlow(!ExistingTracker->RegisteredComponents.Contains(SkinnedComponent)); // We have already been registered? Something has gone very wrong!



ExistingTracker->RegisteredComponents.Add(SkinnedComponent);

FAnimUpdateRateParameters
UpdateRateParams = &ExistingTracker->UpdateRateParameters;

SkinnedComponent->OnAnimUpdateRateParamsCreated.ExecuteIfBound(UpdateRateParams);



return UpdateRateParams;

}



//------------------//



//-----USkeletalMeshComponent.cpp-----------------//

初期値を入れておく。値はFAnimUpdateRateParametersに合わせました。

USkeletalMeshComponent::USkeletalMeshComponent(const FObjectInitializer& ObjectInitializer)

: Super(ObjectInitializer)

{









//============ yuu_kajii@winter-crown-works.com =========================//

#if 1

BaseVisibleDistanceFactorThesholds.Add(0.24f);

BaseVisibleDistanceFactorThesholds.Add(0.12f);

bInterpolateSkippedFrames = false;

BaseNonRenderedUpdateRate = 4;

MaxEvalRateForInterpolation = 4;

ShiftBucket = EUpdateRateShiftBucket::ShiftBucket0;

#endif

//============ ================================ =========================//



//---------------------------------------------------------------//

 

注意:

BaseVisibleDistanceFactorThesholdsの要素数を増やした場合、MaxEvalRateForInterpolation も増やさないとデフォルトでは4フレーム目のスキップから補間が切られるので注意。

BaseNonRenderedUpdateRate は描画されていないときのスキップフレームです。

 

 

以上です。これで4フレームスキップの補間あり等がSkeletalMeshComponentから設定が行えます。

参考になる方いらっしゃれば幸いです。

情報共有用なので、こちらで回答終了とさせていただきます。