目标

HoudiniEngine会尝试把前缀为unreal_uproperty_的attribute转换为UE中的UProperty。(详见官方文档)
本篇的目标是观察这一过程是怎样实现的。

0. 准备测试用HDA

首先,准备一个可以让这段逻辑出现的HDA。

我这里用一条线创建出五个点:

houdini选择连接的边_houdini


随后,用PointWrangle节点来创建一段逐Point执行的vex代码:

//指定生成点光源Actor
s@unreal_instance = "PointLight";
//光源强度逐渐变强
@unreal_uproperty_Intensity = pow(4,@ptnum);

即,使用unreal_instance将每个点指定为点光源。

然后就是本篇关注的,使用unreal_uproperty_设定通用属性Intensity

houdini选择连接的边_houdini选择连接的边_02


Intensity是递增的,所以这个HDA放到场景中可以看到:

houdini选择连接的边_houdini选择连接的边_03

1. 找到观察代码的起点。

那么,从哪开始观察这个过程的逻辑呢?


首先,这段逻辑肯定和这个前缀名有关,所以可以尝试在代码中搜索“unreal_uproperty_”,
发现在 \HoudiniEngine\Private\HoudiniEnginePrivatePCH.h 已经被定义成了宏:

#define HAPI_UNREAL_ATTRIB_GENERIC_UPROP_PREFIX				"unreal_uproperty_"

接着,就要搜索HAPI_UNREAL_ATTRIB_GENERIC_UPROP_PREFIX了。有三个部分:


第一部分,是FHoudiniEngineUtils::GetGenericPropertiesAttributes

houdini选择连接的边_houdini_04


但我这里断点并没有触发,所以忽略这里。


第二部分,在FHoudiniOutputTranslator::UpdateOutputs中:

houdini选择连接的边_houdini选择连接的边_05


但是这里并没有得到有效的 GenericAttributes ,所以这次忽略。


第三部分,是FHoudiniInstanceTranslator::GetGenericPropertiesAttributes

houdini选择连接的边_#define_06

这里断点触发了,且可以看到得到了Intensity这个属性并输出到了OutPropertyAttributes中。
所以这就是观察代码的起点了。

2. 属性被存入 InstancedOutputPartData.AllPropertyAttributes

继续执行代码,可以看到在外层FHoudiniInstanceTranslator::CreateAllInstancersFromHoudiniOutput中,属性被存入 InstancedOutputPartData.AllPropertyAttributes

houdini选择连接的边_houdini选择连接的边_07

3. 属性被传入FHoudiniInstanceTranslator::UpdateGenericPropertiesAttributes

继续调试,可以看到属性最后被传入FHoudiniInstanceTranslator::UpdateGenericPropertiesAttributes

houdini选择连接的边_点光源_08

4. 每个属性逐个调用 FHoudiniGenericAttribute::UpdatePropertyAttributeOnObject

每个属性在FHoudiniGenericAttribute::UpdatePropertyAttributeOnObject被传入:

houdini选择连接的边_houdini选择连接的边_09

可以看到在这里,每个属性都尝试设定到Object上。此时的Object就是点光源Actor。值得一提的是,这里也会单独处理一些“特殊”属性:

houdini选择连接的边_houdini选择连接的边_10


如果以上的“特殊”情况都没有进入,则最后会尝试在Object上找这个属性:

houdini选择连接的边_搜索_11

5. 使用 FHoudiniGenericAttribute::FindPropertyOnObject 找到对应的属性

可以看到,除了Object本身之外,他还会找“内嵌”的类(不过这里只有StaticMesh,也许可以自己补充)。另外,还会找Actor的组件:

houdini选择连接的边_houdini选择连接的边_12

6. 使用 TFieldIterator 遍历找到对应名字的属性

houdini选择连接的边_houdini选择连接的边_13

总结:

  1. 统计所有前缀为unreal_uproperty_的属性。
  2. 尝试将每个属性设置到Object上,有些属性被特别设置了,详见FHoudiniGenericAttribute::UpdatePropertyAttributeOnObject
  3. 尝试根据名字找到Object对应的属性。方法是通过TFieldIterator<FProperty>遍历所有属性并比较名字。另外,相关的Object也被考虑,如Actor的组件,详见FHoudiniGenericAttribute::FindPropertyOnObject