【UE4】ConstructionScriptでのGetSocketTransformがおかしい?(BP)+フレームレートの取得(C++)/第13回UE4ぷちコン進捗 - 2020/03/21


株式会社ヒストリアさん主催の第13回UE4ぷちコンの作業進捗。
昨夜ハマったネタの備忘録として。

ConstructionScript × GetSocketTransform

上は、コンストラクションスクリプト上で、ドラゴンの Head ボーンの World Transform を取得するノードグラフ。

Draw Debug Coordinate Cross は、ただ単に座標軸を書くためのもの。
UE4 標準の Draw Debug Coordinate System もよく使うが、マイナス軸の表示も欲しいときはこういうのを使っている。

この結果、エディタのビューポートに表示される絵はこうなる:

頭と全然違う位置に座標軸のデバッグ表示が出てしまっている。

ドラゴンの体を通るピンクのラインは、ビューポート内の Show メニューの Developer > Bones を ON にしたもの。

おおむね昨日一日、この問題で悶絶していた。
もともとは、頭(≒顎)に対する餌の位置を探していたので、逆行列の計算とかがアレコレ入っていて、掛け算の順番を間違ったか?とか、World Spaceじゃなくて、Component Spaceなのか?とか、そっちの方を必死に追いかけてしまっていた。

ふと、思い立って、Tickでもデバッグ表示してみたのがこちら:

あってんじゃん!

ボーン表示はコンソールコマンド show Bones

ということで、今のところ、Construction Script で Get Socket Transform をすると、正しくない値が返ってくる可能性があるかもしれません。実行中の Get Socket Transform は正しい値を返します。(UE4.24.3)

例えば、グレイマンでは正しく出るのではないかとか、Get Socket Location ならどうなのか、など、他のシチュエーションでの追加調査をする余裕はないので、このまま放置します。すみません。(…ぷちコン締め切りまで1週間!)

ざっくり何をやったかだけ列挙すると:

  • Construction Script での動作
  • Skeletal Mesh Component (=ドラゴン) は、Yaw回転が-90度で、2倍のスケール
  • Skeletal Mesh Component の Override Animation Data で、エディタ上で表示するアニメーションとフレーム番号を指定。
    • 【追記】IsPlaying = True, PlayRate = 0.0 でも、IsPlaying = False, PlayRate = 1.0 でも、状況は変わらず。
  • その後、Get Socket Transform で頭ボーンの Transform を取得

こういう流れでやっています。

AnimSequenceからフレームレートなどを取得する

Blueprintでは取得できない、アニメーションシーケンスの総フレーム数、フレームレートなどについて。
もう取れないものだとずっと諦めていたのだが、今更ながら、C++でサクっと取得できることに気づいた。

C++ で Blueprint Function Library を作って、一気に便利に取得するようにした例:

GetAnimFrameInfo()
void UMyBlueprintFunctionLibrary::GetAnimFrameInfo(UAnimSequence* InAnimSequence,
    bool& OutSuccess, int& OutNumFrames, float& OutPlayLength, float& OutFrameRate)
{
    if (!InAnimSequence)
    {
        UE_LOG(LogMyLibrary, Error, TEXT("GetAnimFrameInfo()  InAnimSequence must not be a nullptr."));
        OutSuccess = false;
        return;
    }

    OutSuccess = true;
    OutNumFrames = InAnimSequence->GetNumberOfFrames();
    OutPlayLength = InAnimSequence->GetPlayLength();
    OutFrameRate = InAnimSequence->GetFrameRate();
}

【注意】自作関数GetAnimFrameInfo()の第一引数の型がconst UAnimSequence*ではなく、UAnimSequence*なのは、GetPlayLength()だけconst関数ではないため。(泣く泣く)

ついでに便利そうな関数も

後日談 (2020/05/01)
UAnimSequenceBase::GetTimeAtFrame() も UAnimSequence::GetFrameAtTime() も、WITH_EDITOR 関数だった。
パッケージビルドをするとビルドエラーが出る。
これらは、Editor 専用モジュールでしか使ってはいけない。

フレーム番号と時間(秒)の変換

#if WITH_EDITOR

float UMyBlueprintFunctionLibrary::GetAnimTimeAtFrame(const UAnimSequence* InAnimSequence, int InFrame)
{
    if (!InAnimSequence)
    {
        UE_LOG(LogMyLibrary, Error, TEXT("GetAnimTimeAtFrame()  InAnimSequence must not be a nullptr."));
        return 0.0f;
    }

    return InAnimSequence->GetTimeAtFrame(InFrame);
}


int UMyBlueprintFunctionLibrary::GetAnimFrameAtTime(const UAnimSequence* InAnimSequence, float InTime)
{
    if (!InAnimSequence)
    {
        UE_LOG(LogMyLibrary, Error, TEXT("GetAnimFrameAtTime()  InAnimSequence must not be a nullptr."));
        return 0.0f;
    }

    return InAnimSequence->GetFrameAtTime(InTime);
}

#endif // WITH_EDITOR

こちらはconst UAnimSequence*型で行ける。