Flag Engine(动画系统)学习笔记(十一)——其他

2021SC@SDUSC

// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.

#pragma once

#include "Engine/Scripting/ScriptingType.h"
#include "Engine/Core/Delegate.h"

class TaskGraphSystem;
class AnimatedModel;
class Asset;

/// <summary>
/// The animations playback service.
/// </summary>
API_CLASS(Static) class FLAXENGINE_API Animations
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Animations);

    /// <summary>
    /// The system for Animations update.
    /// </summary>
    API_FIELD(ReadOnly) static TaskGraphSystem* System;

#if USE_EDITOR
    // Custom event that is called every time the Anim Graph signal flows over the graph (including the data connections). Can be used to read and visualize the animation blending logic. Args are: anim graph asset, animated object, node id, box id
    API_EVENT() static Delegate<Asset*, ScriptingObject*, uint32, uint32> DebugFlow;
#endif

    /// <summary>
    /// Adds an animated model to update.
    /// </summary>
    /// <param name="obj">The object.</param>
    static void AddToUpdate(AnimatedModel* obj);

    /// <summary>
    /// Removes the animated model from update.
    /// </summary>
    /// <param name="obj">The object.</param>
    static void RemoveFromUpdate(AnimatedModel* obj);
};

上面的为animations.h 是animations.cpp的头文件

可以看到animations主要有三个函数

TaskGraphSystem* System  动画数据的上传

AddToUpdate(AnimatedModel* obj) 将动画模型传入数据块中

RemoveFromUpdate(AnimatedModel* obj);动画模型从数据块中取出

#include "Animations.h"
#include "Engine/Engine/Engine.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Level/Actors/AnimatedModel.h"
#include "Engine/Engine/Time.h"
#include "Engine/Engine/EngineService.h"
#include "Engine/Threading/TaskGraph.h"

class AnimationsService : public EngineService
{
public:

    AnimationsService()
        : EngineService(TEXT("Animations"), -10)
    {
    }

    bool Init() override;
    void Dispose() override;
};

class AnimationsSystem : public TaskGraphSystem
{
public:
    float DeltaTime, UnscaledDeltaTime, Time, UnscaledTime;
    void Job(int32 index);
    void Execute(TaskGraph* graph) override;
    void PostExecute(TaskGraph* graph) override;
};

AnimationsService AnimationManagerInstance;
Array<AnimatedModel*> UpdateList;
TaskGraphSystem* Animations::System = nullptr;
#if USE_EDITOR
Delegate<Asset*, ScriptingObject*, uint32, uint32> Animations::DebugFlow;
#endif

bool AnimationsService::Init()
{
    Animations::System = New<AnimationsSystem>();
    Engine::UpdateGraph->AddSystem(Animations::System);
    return false;
}

void AnimationsService::Dispose()
{
    UpdateList.Resize(0);
    SAFE_DELETE(Animations::System);
}

void AnimationsSystem::Job(int32 index)
{
    PROFILE_CPU_NAMED("Animations.Job");
    auto animatedModel = UpdateList[index];
    auto skinnedModel = animatedModel->SkinnedModel.Get();
    auto graph = animatedModel->AnimationGraph.Get();
    if (graph && graph->IsLoaded() && graph->Graph.CanUseWithSkeleton(skinnedModel)
#if USE_EDITOR
        && graph->Graph.Parameters.Count() == animatedModel->GraphInstance.Parameters.Count() // It may happen in editor so just add safe check to prevent any crashes
#endif
    )
    {
#if COMPILE_WITH_PROFILER && TRACY_ENABLE
        const StringView graphName(graph->GetPath());
        ZoneName(*graphName, graphName.Length());
#endif

        // Prepare skinning data
        animatedModel->SetupSkinningData();

        // Animation delta time can be based on a time since last update or the current delta
        float dt = animatedModel->UseTimeScale ? DeltaTime : UnscaledDeltaTime;
        float t = animatedModel->UseTimeScale ? Time : UnscaledTime;
        const float lastUpdateTime = animatedModel->GraphInstance.LastUpdateTime;
        if (lastUpdateTime > 0 && t > lastUpdateTime)
        {
            dt = t - lastUpdateTime;
        }
        dt *= animatedModel->UpdateSpeed;
        animatedModel->GraphInstance.LastUpdateTime = t;

        // Evaluate animated nodes pose
        graph->GraphExecutor.Update(animatedModel->GraphInstance, dt);

        // Update gameplay
        animatedModel->OnAnimationUpdated_Async();
    }
}

void AnimationsSystem::Execute(TaskGraph* graph)
{
    if (UpdateList.Count() == 0)
        return;

    // Setup data for async update
    const auto& tickData = Time::Update;
    DeltaTime = tickData.DeltaTime.GetTotalSeconds();
    UnscaledDeltaTime = tickData.UnscaledDeltaTime.GetTotalSeconds();
    Time = tickData.Time.GetTotalSeconds();
    UnscaledTime = tickData.UnscaledTime.GetTotalSeconds();

#if USE_EDITOR
    // If debug flow is registered, then warm it up (eg. static cached method inside DebugFlow_ManagedWrapper) so it doesn't crash on highly multi-threaded code
    if (Animations::DebugFlow.IsBinded())
        Animations::DebugFlow(nullptr, nullptr, 0, 0);
#endif

    // Schedule work to update all animated models in async
    Function<void(int32)> job;
    job.Bind<AnimationsSystem, &AnimationsSystem::Job>(this);
    graph->DispatchJob(job, UpdateList.Count());
}

void AnimationsSystem::PostExecute(TaskGraph* graph)
{
    PROFILE_CPU_NAMED("Animations.PostExecute");

    // Update gameplay
    for (int32 index = 0; index < UpdateList.Count(); index++)
    {
        auto animatedModel = UpdateList[index];
        auto skinnedModel = animatedModel->SkinnedModel.Get();
        auto animGraph = animatedModel->AnimationGraph.Get();
        if (animGraph && animGraph->IsLoaded() && animGraph->Graph.CanUseWithSkeleton(skinnedModel)
#if USE_EDITOR
            && animGraph->Graph.Parameters.Count() == animatedModel->GraphInstance.Parameters.Count() // It may happen in editor so just add safe check to prevent any crashes
#endif
        )
        {
            animatedModel->OnAnimationUpdated_Sync();
        }
    }

    // Cleanup
    UpdateList.Clear();
}

void Animations::AddToUpdate(AnimatedModel* obj)
{
    UpdateList.Add(obj);
}

void Animations::RemoveFromUpdate(AnimatedModel* obj)
{
    UpdateList.Remove(obj);
}

animations的cpp文件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值