目标

UHoudiniAssetComponent的成员 AssetState,它是一个枚举EHoudiniAssetState

enum class EHoudiniAssetState : uint8
{// Loaded / Duplicated HDA,// Will need to be instantiated upon change/updateNeedInstantiation,// Newly created HDA, fetch its default parameters then proceed to PreInstantiationNewHDA,// Newly created HDA, after default parameters fetch, needs to be instantiated immediatelyPreInstantiation,// Instantiating task in progressInstantiating,    // Instantiated HDA, needs to be cooked immediatelyPreCook,// Cooking task in progressCooking,// Cooking has finishedPostCook,// Cooked HDA, needs to be processed immediatelyPreProcess,// Processing task in progressProcessing,// Processed / Updated HDA// Will need to be cooked upon change/updateNone,// Asset needs to be rebuilt (Deleted/Instantiated/Cooked)NeedRebuild,// Asset needs to be deletedNeedDelete,// DeletingDeleting,// Process component template. This is ticking has very limited// functionality, typically limited to checking for parameter updates// in order to trigger PostEditChange() to run construction scripts again.ProcessTemplate,
};

它表示了当前 HAC 的状态。

当一个 HDA 被放入场景中时,就会创建一个HAC。接着由HAC负责维护 HDA 的 Cook 过程。因此观察 HAC 的状态的变化有助于理解 “编辑器中HDA的Cook流程”。

本篇的目标是对 HAC 在各个状态的变化过程有个初步的认知。

准备

设置AssetState的逻辑在哪?

AssetState” 和 “设置AssetState的接口” 都是 protected 成员,一般情况外部无法访问,最理想的情况是只用看 HAC 内部的逻辑就能明白流程,但是 HAC 有一些友元类:

 friend class FHoudiniEngineManager;friend struct FHoudiniOutputTranslator;friend struct FHoudiniInputTranslator;friend struct FHoudiniSplineTranslator;friend struct FHoudiniParameterTranslator;friend struct FHoudiniPDGManager;friend struct FHoudiniHandleTranslator;#if WITH_EDITORONLY_DATAfriend class FHoudiniAssetComponentDetails;
#endiffriend class FHoudiniEditorEquivalenceUtils;

这使得设置 AssetState 的逻辑还被分散到了这些友元类中,使得还需要看这些类的逻辑才能搞清楚流程。

AssetState变化时打印

AssetState 变化时打印其值会对观察帮助很大。

虽然一些友元类可以直接访问 AssetState,但是搜索后没有看到直接访问的,都是通过接口函数SetAssetState访问的。因此在这个函数中添加打印的逻辑就能涵盖所有外部访问的情况了。

HAC 内部直接访问 AssetState 的地方除了 SetAssetState 之外,也只有两处:构造函数、 PostEditImport 函数。


打印时,由于 AssetState 是个枚举类。为了更容易理解可以将其转换为字符串来打印。(UE中枚举转字符串的逻辑可见《在UE中获得枚举(UEnum)值对应的字符串》)

代码如下:

DEFINE_LOG_CATEGORY_STATIC(LogHACStateTest, Log, All);
void TestLogHACState(EHoudiniAssetState state, FString FunctionName)
{//获取 UEnum 对象:const UEnum* EnumObject = FindObject<UEnum>(ANY_PACKAGE, TEXT("EHoudiniAssetState"));//获取对应字符串:const FName EnumName = (EnumObject->GetNameByValue((int64)state));//测试打印当前值UE_LOG(LogHACStateTest, Warning, TEXT("AssetState = %s (Function: %s)"), *EnumName.ToString(), *FunctionName);
}

随后,将这个函数加到 HAC 里改变 AssetState 的三处。

观察“将HDA拖入场景”过程中的状态变化

“将HDA拖入场景”是个最基础的流程,可以看到以下Log:

LogHACStateTest: Warning: AssetState = EHoudiniAssetState::NewHDA (Function: Construct)
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::NewHDA (Function: Construct)
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::PreInstantiation (Function: SetAssetState)
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::Instantiating (Function: SetAssetState)
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::PreCook (Function: SetAssetState)
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::Cooking (Function: SetAssetState)
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::PostCook (Function: SetAssetState)
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::PreProcess (Function: SetAssetState)
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::Processing (Function: SetAssetState)
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::None (Function: SetAssetState)

下面,深入观察每次进入另一个状态时的上下文,以及相关的发现。

NewHDA

首先很明显, NewHDA 是在构造函数中作为一个初值。

PreInstantiation

随后,当HoudiniEngineManager看到一个HAC在NewHDA状态时就将它变为PreInstantiation

这是在Tick中调用的:

FHoudiniEngineManager::Tick 是在一开始就被安排一直Tick的:

Instantiating

之后的情况同上,也是HoudiniEngineManager看到一个HAC在PreInstantiation状态时就将它变为Instantiating

但这里要注意的是它先调用了StartTaskAssetInstantiation。这是向HoudiniEngineScheduler中增加了一个AssetInstantiation类型的任务:

需要注意的是,HoudiniEngineScheduler是一个FRunnable,它是在另一个线程中Tick的:

它专门运行一些HAPI,比如这里的创建节点:

PreCook

HoudiniEngineManagerInstantiating时会一直调用UpdateInstantiating,如果成功就会设置HAC为新的状态。

HoudiniEngineScheduler处理结束后,会添加一个Success的TaskInfo

这时在UpdateInstantiating中就可以知道成功的消息

之后,就会设置新的状态为PreCook

Cooking

这里的行为类似于Instantiating

它向HoudiniEngineScheduler加入了一个AssetCooking类型的任务。
随后将HAC的状态置为Cooking

同样,HoudiniEngineScheduler会对节点进行Cook:

PostCook

这里的行为类似于之前的PreCook
HoudiniEngineManagerCooking时会一直调用UpdateCooking,如果成功就会设置HAC为新的状态。

HoudiniEngineScheduler处理结束后,会添加一个Success的TaskInfo

这时在UpdateCooking中就可以知道成功的消息。然后将HAC状态设置为PostCook

PreProcess

然后,HoudiniEngineManager会对处于PostCook的HAC调用PostCook函数,如果成功则设置状态为PreProcess

Processing

随后,立即被设置为Processing状态:

None

随后同上,立即被设置为None状态。

FHoudiniEngineManager::Tick中的循环

ProcessComponentFHoudiniEngineManager::Tick中的一个循环中执行:

这意味着,对于这些 bKeepProcessing = true 的状态,他们在进入之后,立即又进入下一个状态,而不是等待下一次Tick。

如果在FHoudiniEngineManager::Tick中加一个Log,则可以看到:

LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::NewHDA (Function: Construct)
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::NewHDA (Function: Construct)
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::PreInstantiation (Function: SetAssetState)
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::Instantiating (Function: SetAssetState)
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::PreCook (Function: SetAssetState)
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::Cooking (Function: SetAssetState)
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::PostCook (Function: SetAssetState)
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::PreProcess (Function: SetAssetState)
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::Processing (Function: SetAssetState)
LogHACStateTest: Warning: AssetState = EHoudiniAssetState::None (Function: SetAssetState)
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick
LogHACStateTest: Warning: FHoudiniEngineManager::Tick

可以看到,bKeepProcessing = true的状态在处理完之后确实立马进入下一个状态,而不是在下一次Tick中再进入。
(除了 NewHDA 是个例外,首先它出现了两次,可能是因为UE在拖动HDA到场景中的时候调用了两次构造函数。随后看见它并没有马上进入下一个状态,应该是因为状态没有发生变化所以让 bKeepProcessing 成为了 false)

结论

首先,对HAC的状态变化影响最大的显然是FHoudiniEngineManager
FHoudiniEngineManager会随着引擎的每次Tick也会Tick自己,并针对每个状态而做不同的行为。

另一个影响很大的是HoudiniEngineScheduler,比如当HAC的状态进入InstantiatingCooking时,一个任务会被添加到HoudiniEngineScheduler中,并在另一个线程中执行。而此时FHoudiniEngineManager会一直检查是否执行好,如果执行完毕就进入下一个状态。

对于“将HDA拖入场景”,HAC的状态流程如下:

对于这些状态,它在进入后,会立即在本次Tick中又继续进入下一个状态:

  • NewHDA
  • PreInstantiation
  • PreCook
  • PostCook
  • PreProcess
  • Processing

当然,这样概括HAC的变化确实过于简单了,但如果想要获取更复杂的信息,也可以仿照本篇的方法来观察。例如:

  • 如果想知道更具体的逻辑,可以从FHoudiniEngineManager::Tick入手,特别是其中调用的ProcessComponent
  • 在状态变化的地方加Log可以知道有哪些状态发生了并且他们的顺序是什么,加断点可以知道其上下文。
  • FHoudiniEngineScheduler::AddTask加断点可以知道什么时候有任务加入Scheduler,并且任务是什么。
  • FHoudiniEngineScheduler::ProcessQueuedTasks中有在Scheduler线程中执行各种任务的具体逻辑。

简单观察HoudiniAssetComponent状态(AssetState)的变化过程相关推荐

  1. python matplotlib 播放图片变化过程

    最近想将原图片和处理后的图片放在一起观察图片的变化过程.但是网上并么有找到有用的示例代码,所以粘出来和大家分享一下. import numpy as np import matplotlib.pypl ...

  2. synchronized的使用和底层原理、锁状态的膨胀升级过程

    文章目录 1. synchronized介绍 2. synchronized底层原理 3. synchronized锁的膨胀升级过程 4. synchronized锁状态的记录位置 5. synchr ...

  3. 以太网 传统STP生成树的BPDU介绍、STP端口状态介绍与切换过程,STP详细的工作过程。

    2.10.1 以太网 传统STP生成树(STP BPDU.STP端口状态.STP工作过程) STP生成树协议的之间的交互通过STP BPDU(根协议数据单元,Bridge Protocol Data ...

  4. 目前住院病人主要由护士护理,这样做不仅需要大量护士,而且由于不能随时观察危害病人的病情变化,还可能会延误抢救时机.某医院打算开发一个以计算机为中心的患者监护系统,试写出问题定义,并且分析开发这个系统

    目前住院病人主要由护士护理,这样做不仅需要大量护士,而且由于不能随时观察危害病人的病情变化,还可能会延误抢救时机.某医院打算开发一个以计算机为中心的患者监护系统,试写出问题定义,并且分析开发这个系统的 ...

  5. stm32c8t6的can通信实验代码_TCP的连接建立与关闭状态及数据传输通信过程【含有 PHP socket API 测试实验代码】...

    php中文网最新课程 每日17点准时技术干货分享 本文章使用 PHP 代码来测试 TCP 传输层的一个通信过程.TCP/IP 协议关于该协议的详细内容可自行查阅 <>PHP 的 tcp/u ...

  6. Flink并行度优先级_集群操作常用指令_运行组件_任务提交流程_数据流图变化过程

    Flink并行度优先级(从高到低) sum(1).setParallelism(1) env.setParallelism(1) ApacheFlinkDashboard任务添加并行度配置 flink ...

  7. 目前住院病人主要由护士护理,这样做不仅需要大量护士,而且由于不能随时观察危重病人的病情变化,还可能会延误抢救时机。某医院打算开发一个以计算机为中心的监护系统,试写出问题定义并且分析开发这个系统的可行性

    目前住院病人主要由护士护理,这样做不仅需要大量护士,而且由于不能随时观察危重病人的病情变化,还可能会延误抢救时机.某医院打算开发一个以计算机为中心的监护系统,试写出问题定义,并且分析开发这个系统的可行 ...

  8. 目前住院病人主要由护士护理,这样做不仅需要大量护士,而且由于不能随时观察危重病人的病情变化,还会延误抢救时机。某医院打算开发一个以计算机为中心的患者监护系统,请用数据流图描述下面系统的业务流程。

    目前住院病人主要由护士护理,这样做不仅需要大量护士,而且由于不能随时观察危重病人的病情变化,还会延误抢救时机.某医院打算开发一个以计算机为中心的患者监护系统,请用数据流图描述下面系统的业务流程(画出两 ...

  9. 目前住院病人主要由护士护理这样做不仅需要大量护士而且由子不能随时观察危重病人的病情变化还可能会延误抢救时机.某医院打算开发-个以计算机为中心的患者监护系统试写出问题定义并且分析开发这个系统的可行性.

    目前住院病人主要由护士护理这样做不仅需要大量护士而且由子不能随时观察危重病人的病情变化还可能会延误抢救时机.某医院打算开发-个以计算机为中心的患者监护系统试写出问题定义并且分析开发这个系统的可行性. ...

最新文章

  1. 亮剑.NET的系列文章之.NET实现三层架构(三)
  2. html5 子元素选择器,CSS子元素选择器 - HTML电子邮件
  3. python爬虫能干什么-总算发现python爬虫能够干什么
  4. struts2 datetimepicker标签的使用
  5. Python是一门什么样的语言
  6. Linux i2c子系统驱动probe
  7. 桌面软件打开都会变成计算机,我不小心把电脑界面程序的打开方式都变成一种了,怎么还原啊?...
  8. PyTorch的Tensor(张量)
  9. Win2003的IIS设置
  10. php修改密码功能md5,php – 更改密码哈希类型的最有效方法(md5到sha1)
  11. mysql常用的语句_MySQL常用语句集锦
  12. iOS开发之TableView去掉单个cell的间隔线和去掉全部间隔线和去掉tableView多余的间隔线
  13. SQL:MongoDB简述
  14. epub电子书--目录结构介绍
  15. 顺序表的基本操作(C语言实现,简单易懂!)
  16. php 串口 主板,图解主板插槽:教你选对串口卡
  17. unity2018 Image使用Sliced九宫格进行调整
  18. Log-normal distribution对数正态分布
  19. python轻松生成pdf文档
  20. 计算某天是某年的第多少天

热门文章

  1. Notepad++的字体设置为 Consolas 和微软雅黑混合字体转载
  2. C# Chart 曲线(多曲线展示)
  3. 蓝桥杯部分题型(奇怪的比赛,电话号码,palindrome)
  4. codeforce-298B Sail(模拟)
  5. 1、 Seata快速开始
  6. python--unicodedata用法
  7. 关于android 在黑屏情况下wifi下载速度慢的问题的解决。
  8. alpine linux 安装教程,Alpine linux硬盘安装
  9. 钣金缺口lisp_钣金件的编程展开及切割系统
  10. (笔记)第一章:零基础入门深度学习