在Unity中制作Houdini工具
需求说明在项目中,我们给美术做了很多Houdini工具,但美术在使用的适合需要把HDA手动拖到场景中并配置输入。
为了减少美术使用工具的障碍(最理想的状态应该是让美术对Houdini无感,不过我觉得HDA的默认面板还是可以一用的),需要在Unity里开发一些小工具来辅助美术的工作。
制作工具你需要:对Unity Editor的一点了解 + 对HoudiniEngine For Unity的脚本的一点了解
一些具体功能的实现方式
好像没什么好描述说明的,直接贴代码吧,换个项目也能复用。
使用Unity C#来加载Houdini HDA
public static HEU_HoudiniAsset houdiniAsset = null; //为了后续赋值之类的需要HEU_HoudiniAsset的操作,要记录它
PTStartTool(path, out houdiniAsset); //前面那个参数是个Asset开头的路径string
//其实好像不需要拆成这么多个方法 ↓
public static void PTStartTool(string HDAAssetPath, out HEU_HoudiniAsset mHoudiniAsset)
{
GameObject rootGO = PCGToolsUtils.PTLoadHoudiniHDA(HDAAssetPath);
HEU_HoudiniAsset houdiniAsset = PCGToolsUtils.PTQueryHoudiniAsset(rootGO);
mHoudiniAsset = houdiniAsset;
if (houdiniAsset == null)
{
return;
}
PCGToolsUtils.PTCookAsset(houdiniAsset);
}
public static GameObject PTLoadHoudiniHDA(string HDAAssetPath)
{
string HDAFullPath = HEU_AssetDatabase.GetAssetFullPath(HDAAssetPath);
if (string.IsNullOrEmpty(HDAFullPath))
{
HEU_Logger.LogErrorFormat("Unable to load houdini asset at path: {0}", HDAAssetPath);
return null;
}
HEU_SessionBase session = HEU_SessionManager.GetOrCreateDefaultSession();
GameObject rootGO = HEU_HAPIUtility.InstantiateHDA(HDAFullPath, Vector3.zero, session, true);
if (rootGO != null)
{
HEU_EditorUtility.SelectObject(rootGO);
}
return rootGO;
}
public static HEU_HoudiniAsset PTQueryHoudiniAsset(GameObject rootGO)
{
HEU_HoudiniAssetRoot heuRoot = rootGO.GetComponent<HEU_HoudiniAssetRoot>();
if (heuRoot == null)
{
HEU_Logger.LogWarningFormat(&#34;Unable to get the HEU_HoudiniAssetRoot from gameobject: {0}. Not a valid HDA.&#34;, rootGO.name);
return null;
}
if (heuRoot.HoudiniAsset == null)
{
HEU_Logger.LogWarningFormat(&#34;Unable to get the HEU_HoudiniAsset in root gameobject: {0}. Not a valid HDA.&#34;, rootGO.name);
return null;
}
return heuRoot.HoudiniAsset;
}
用脚本设置HDA工具参数
//直接用节点的名字就可以赋值
HEU_ParameterUtility.SetString(houdiniAsset, &#34;name&#34;, &#34;a name&#34;);
HEU_ParameterUtility.SetToggle(houdiniAsset, &#34;input&#34;, true);
设置完参数以后需要手动Recook才能看到生成结果变化
//Recook
houdiniAsset.RequestCook(bCheckParametersChanged: true, bAsync: false, bSkipCookCheck: true, bUploadParameters: true);
//有的时候Recook没有反应(原因不明),可以尝试Rebuild
houdiniAsset.RequestReload(bAsync: false);
赋值的前提是要知道节点的数据类型,数据类型当然可以打开Houdini直接查看,不过也可以在Unity里直接检查:
public static void PTCheckParms(HEU_HoudiniAsset houdiniAsset)
{
List<HEU_ParameterData> parms = houdiniAsset.Parameters.GetParameters();
if (parms == null || parms.Count == 0)
{
HEU_Logger.LogFormat(&#34;No parms found&#34;);
return;
}
StringBuilder sb = new StringBuilder();
foreach (HEU_ParameterData parmData in parms)
{
sb.AppendLine(string.Format(&#34;Parm: name={0}, type={1}&#34;, parmData._labelName, parmData._parmInfo.type));
}
HEU_Logger.Log(&#34;Parameters: \n&#34; + sb.ToString());
}
这个脚本的输出大概是这样的,像是图上这种,很容易就可以看出数据类型是Int,Float和Toggle,可以直接用HEU_ParameterUtility.SetXXX赋值。
除了这些,常用的还有HDA组件还有按钮,虽然按钮的type末尾是INT_END,但不能用SetInt赋值:
if (GUILayout.Button(&#34;获取按钮值&#34;))
{
int tmpInt;
HEU_ParameterData buttonData = houdiniAsset.Parameters.GetParameter(&#34;cookbutton&#34;);
tmpInt = buttonData._intValues;
Debug.Log($&#34;获取按钮值结果:{tmpInt}&#34;); //0
}
if (GUILayout.Button(&#34;触发按钮&#34;))
{
houdiniAsset.Parameters.TriggerButtonParameter(&#34;cookbutton&#34;);
//似乎也可以靠 buttonData._intValues=1 来触发按钮,之前试过我有点忘了
}
用脚本设置保存和读取HDA预设
//保存HDA配置到路径
public static void SaveHDAPresetToDir(string fileName, string folderDir, HEU_HoudiniAsset houdiniAsset) {
string filePattern = &#34;heupreset&#34;;
string newPath = EditorUtility.SaveFilePanel(&#34;Save HDA preset&#34;, folderDir, fileName + &#34;.&#34; + filePattern, filePattern);
if (newPath != null && !string.IsNullOrEmpty(newPath))
{
HEU_AssetPresetUtility.SaveAssetPresetToFile(houdiniAsset, newPath);
}
}
//从路径加载HDA配置
public static void LoadHDAPresetFromDir(string folderDir, HEU_HoudiniAsset houdiniAsset)
{
string filePattern = &#34;heupreset,preset&#34;;
string newPath = EditorUtility.OpenFilePanel(&#34;Load HDA preset&#34;, folderDir, filePattern);
if (newPath != null && !string.IsNullOrEmpty(newPath))
{
HEU_AssetPresetUtility.LoadPresetFileIntoAssetAndCook(houdiniAsset, newPath);
}
}
if (GUILayout.Button(&#34;保存配置&#34;, PTStyles.PTButtonStyle))
{
string presetFolderPath = &#34;Assets/Res/Houdini/HDAPreset&#34;;
SaveHDAPresetToDir(&#34;Config&#34;, presetFolderPath, houdiniAsset);
}
if (GUILayout.Button(&#34;加载配置&#34;, PTStyles.PTButtonStyle))
{
string presetFolderPath = &#34;Assets/Res/Houdini/HDAPreset&#34;;
LoadHDAPresetFromDir(presetFolderPath, houdiniAsset);
}
用脚本向InputNode中赋值
默认情况下,配置输入的时候需要美术把GameObject一个一个地拖到面板上,这个过程很耗费时间,可以用脚本来完成。
private static HEU_InputObjectInfo CreateInputObjectInfo(GameObject inputGameObject)
{
HEU_InputObjectInfo newObjectInfo = new HEU_InputObjectInfo();
newObjectInfo._gameObject = inputGameObject;
newObjectInfo.SetReferencesFromGameObject();
return newObjectInfo;
}
if (GUILayout.Button(&#34;自动填充输入&#34;))
{
HEU_InputNode node = houdiniAsset.InputNodes; //第一个InputNode
node.InputObjects.Clear(); //清空原有的输入
string fullPath = &#34;Assets/Res/Prefab/Sector/test.prefab&#34;;
GameObject go = AssetDatabase.LoadAssetAtPath<GameObject>(fullPath);
if (go != null)
{
node.InputObjects.Add(CreateInputObjectInfo(go));
}
if (node._uiCache != null)
{
node._uiCache._inputNodeSerializedObject.ApplyModifiedProperties();
}
node.RequiresUpload = true;
node.ClearUICache();
Resources.UnloadUnusedAssets();
}
需要注意的是, node.InputObjects 这个方法在Houdini的脚本中是internal的,只允许同一个程序集的脚本调用。可以用下面的代码来指定internal方法对其它的程序集可用:
#if UNITY_EDITOR
using System.Runtime.CompilerServices;
#endif
脚本说明
目前我的开发涉及到的脚本包括以下这些,浅看一遍就能速成。
利用脚本加载HDA并修改参数的例子:HoudiniEngineUnity\Scripts\Examples\HEU_ExampleEvergreenQuery.cs
HDA的Inspector面板,可以用来找一些默认按钮的具体实现方式:HoudiniEngineUnity\Editor\UI\HEU_HoudiniAssetUI.cs
菜单栏里的面板和功能:HoudiniEngineUnity\Editor\HEU_EditorMenu.cs
InputNode的窗口面板:HoudiniEngineUnity\Editor\UI\HEU_InputNodeUI.cs
参考资料
Unity Editor编辑器功能详解:Unity3d Editor 编辑器扩展功能详解(1) 目录索引
Houdini Engine Scripting API In Unity:
官方API文档,很简洁地梳理了Houdini的Unity插件里的脚本结构:Houdini Engine for Unity: Plugin API
(过期资料)
官方在2014年出过一个教程,API版本太老了,已经没什么用了:Intro to Houdini Engine Scripting API | Collections | SideFX
2018年的一个例子,API版本太老了,已经没什么用了: Digital Asset Runtime Control on Unity Editor using Houdini Engine - YouTube
页:
[1]