Unity Houdini插件编写data Table传递数据给Houdini

上次说到Unity Houdini插件将Tag设为group,里面用到了自定义输入接口。然后那个Houdini教程又给我出难题了,unreal 可以用一种叫data Table的数据结构来完成向Houdini结构化数据的传递(链接),我没找到Unity类似的功能,又得自己写。用chatGPT的话,写起来还是挺容易的。

定义带有数据对象列表的组件

首先得有一个在编辑器里定义结构数据的组件,用于定义数据结构。

public abstract class HEU_PDE_DataTable<T> : MonoBehaviour {public List<T> dataTable;
}
using UnityEngine;
using System.Collections.Generic;[System.Serializable]
public struct TileObject {public string name;public GameObject gameObject;public float height;public int num;public Vector3 N;public Color Cd;
}public class HEU_PDE_TileObject : HEU_PDE_DataTable<TileObject> {}

这里使用了泛型,定义了一个抽象的组件,带有一个List属性,其子类可以定义dataTable的数据结构。

效果如下

接着把这个GameObject传递到Houdini的HDA的属性或输入里。

Houdini定义HDA的参数:

 这里使用了object merge节点,将Object抽取成HDA的参数。

然后在自定义输入接口里面处理DataTable,将每个列表项转换成点的属性。

编辑自定义输入接口

首先更改IsThisInputObjectSupported函数,加入对DataTable的支持

    private bool isDataTable(GameObject gameObject) {// judge if it is a subclass of the HEU_PDE_DataTableMonoBehaviour[] components = gameObject.GetComponents<MonoBehaviour>();Type baseGenericType = typeof(HEU_PDE_DataTable<>);foreach (MonoBehaviour component in components) {Type componentType = component.GetType();Type baseType = componentType.BaseType;if (baseType != null && baseType.IsGenericType && baseType.GetGenericTypeDefinition() == baseGenericType) {return true;}}return false;}public override bool IsThisInputObjectSupported(GameObject inputObject) {if (_inputInterfaceMesh.IsThisInputObjectSupported(inputObject)) return true;if (isDataTable(inputObject)) return true;return false;}

 就是遍历对象的组件,用反射获取其父类,判断父类是不是DataTable。

接着在CreateInputNodeWithDataUpload中遍历DataTable,转换成点属性即可

关键代码是

    switch (fieldType.Name) {case nameof(Double):if (HEU_InputMeshUtility.SetMeshPointAttribute(session, inputNodeID, 0, fieldName,1, (values.Cast<double>().Select(v => (float)v)).ToArray(), ref partInfo)) {continue;}break;case nameof(System.Single):if (HEU_InputMeshUtility.SetMeshPointAttribute(session, inputNodeID, 0, fieldName, 1,(values.Cast<float>()).ToArray(), ref partInfo)) {continue;}break;case nameof(Boolean):if (HEU_InputMeshUtility.SetMeshPointAttribute(session, inputNodeID, 0, fieldName, 1,(values.Cast<bool>().Select(v => new Vector3Int(v ? 1 : 0, 0, 0))).ToArray(), ref partInfo)) {continue;}break;case nameof(Int32):if (HEU_InputMeshUtility.SetMeshPointAttribute(session, inputNodeID, 0, fieldName, 1,(values.Select(v => new Vector3Int((int)v, 0, 0))).ToArray(), ref partInfo)) {continue;}break;case nameof(Color):if (HEU_InputMeshUtility.SetMeshPointAttribute(session, inputNodeID, 0, fieldName, 3,(values.Cast<Color>().Select(v => new Vector3(v.r, v.g, v.b))).ToArray(), ref partInfo, false)) {continue;}break;case nameof(Vector3):if (HEU_InputMeshUtility.SetMeshPointAttribute(session, inputNodeID, 0, fieldName,3, (values.Cast<Vector3>()).ToArray(), ref partInfo, false)) {continue;}break;case nameof(String):if (HEU_InputMeshUtility.SetMeshPointAttribute(session, inputNodeID, 0, fieldName,(values.Cast<string>()).ToArray(), ref partInfo)) {continue;}break;case nameof(GameObject):// Convert to resource file pathif (HEU_InputMeshUtility.SetMeshPointAttribute(session, inputNodeID, 0, fieldName,(values.Select(v => (AssetDatabase.GetAssetPath((GameObject)v)))).ToArray(), ref partInfo)) {continue;}break;}HEU_Logger.LogError(string.Format("Failed to set attribute {0}!", fieldName));return false;

根据不同的C#类型转成对应的点属性

效果:

全部代码

HEU_PDE_DataTable.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public abstract class HEU_PDE_DataTable<T> : MonoBehaviour
{public List<T> dataTable;
}

HEU_PDE_TileObject.cs

using UnityEngine;
using System.Collections.Generic;[System.Serializable]
public struct TileObject {public string name;public GameObject gameObject;public float height;public int num;public Vector3 N;public Color Cd;
}public class HEU_PDE_TileObject : HEU_PDE_DataTable<TileObject> {}

HEU_PDE_InputInterfaceMesh.cs

using HoudiniEngineUnity;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using TMPro;
using UnityEditor;
using UnityEngine;
using static UnityEditor.Searcher.SearcherWindow.Alignment;public class HEU_PDE_InputInterfaceMesh : HEU_InputInterface {
#if UNITY_EDITOR[InitializeOnLoadMethod][UnityEditor.Callbacks.DidReloadScripts]private static void OnScriptsReloaded() {HEU_PDE_InputInterfaceMesh inputInterface = new HEU_PDE_InputInterfaceMesh();HEU_InputUtility.RegisterInputInterface(inputInterface);}
#endifprivate readonly HEU_InputInterfaceMesh _inputInterfaceMesh;public HEU_PDE_InputInterfaceMesh() : base(DEFAULT_PRIORITY + 100)// higher priority{// reflect to get instance of HEU_InputInterfaceMeshType type = typeof(HEU_InputInterfaceMesh);BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;ConstructorInfo privateConstructor = type.GetConstructor(bindingFlags, null, new Type[0], null);_inputInterfaceMesh = (HEU_InputInterfaceMesh)privateConstructor.Invoke(null);}public override bool CreateInputNodeWithDataUpload(HEU_SessionBase session, int connectNodeID, GameObject inputObject, out int inputNodeID) {if (isDataTable(inputObject)) {MonoBehaviour[] components = inputObject.GetComponents<MonoBehaviour>();Type baseGenericType = typeof(HEU_PDE_DataTable<>);inputNodeID = HEU_Defines.HEU_INVALID_NODE_ID;int mergeNodeId = HEU_Defines.HEU_INVALID_NODE_ID;HAPI_PartInfo partInfo = new HAPI_PartInfo();string inputName = null;int newNodeID = HEU_Defines.HEU_INVALID_NODE_ID;session.CreateInputNode(out newNodeID, inputName);if (newNodeID == HEU_Defines.HEU_INVALID_NODE_ID || !HEU_HAPIUtility.IsNodeValidInHoudini(session, newNodeID)) {HEU_Logger.LogError("Failed to create new input node in Houdini session!");return false;}inputNodeID = newNodeID;foreach (MonoBehaviour component in components) {Type componentType = component.GetType();Type baseType = componentType.BaseType;if (baseType != null && baseType.IsGenericType && baseType.GetGenericTypeDefinition() == baseGenericType) {// Get the generic argument typeType dataListType = baseType.GetGenericArguments()[0];// Iterate through the properties of the generic argument typeFieldInfo dataTableInfo = componentType.GetField("dataTable");IList dataTable = (IList)dataTableInfo.GetValue(component);FieldInfo[] fields = dataListType.GetFields();partInfo.pointCount = dataTable.Count;if (!session.SetPartInfo(inputNodeID, 0, ref partInfo)) {HEU_Logger.LogError("Failed to set input part info. ");return false;}if (!HEU_InputMeshUtility.SetMeshPointAttribute(session, inputNodeID, 0, HEU_HAPIConstants.HAPI_ATTRIB_POSITION,3, Enumerable.Repeat(new Vector3(0, 0, 0), partInfo.pointCount).ToArray(), ref partInfo, true)) {HEU_Logger.LogError("Failed to set input geometry position.");return false;}partInfo.pointAttributeCount = fields.Length;foreach (FieldInfo field in fields) {Type fieldType = field.FieldType;string fieldName = field.Name;List<object> values = new();for (int i = 0; i < partInfo.pointCount; i++) {object fieldValue = field.GetValue(dataTable[i]);values.Add(fieldValue);}// Handle available typesswitch (fieldType.Name) {case nameof(Double):if (HEU_InputMeshUtility.SetMeshPointAttribute(session, inputNodeID, 0, fieldName,1, (values.Cast<double>().Select(v => (float)v)).ToArray(), ref partInfo)) {continue;}break;case nameof(System.Single):if (HEU_InputMeshUtility.SetMeshPointAttribute(session, inputNodeID, 0, fieldName, 1,(values.Cast<float>()).ToArray(), ref partInfo)) {continue;}break;case nameof(Boolean):if (HEU_InputMeshUtility.SetMeshPointAttribute(session, inputNodeID, 0, fieldName, 1,(values.Cast<bool>().Select(v => new Vector3Int(v ? 1 : 0, 0, 0))).ToArray(), ref partInfo)) {continue;}break;case nameof(Int32):if (HEU_InputMeshUtility.SetMeshPointAttribute(session, inputNodeID, 0, fieldName, 1,(values.Select(v => new Vector3Int((int)v, 0, 0))).ToArray(), ref partInfo)) {continue;}break;case nameof(Color):if (HEU_InputMeshUtility.SetMeshPointAttribute(session, inputNodeID, 0, fieldName, 3,(values.Cast<Color>().Select(v => new Vector3(v.r, v.g, v.b))).ToArray(), ref partInfo, false)) {continue;}break;case nameof(Vector3):if (HEU_InputMeshUtility.SetMeshPointAttribute(session, inputNodeID, 0, fieldName,3, (values.Cast<Vector3>()).ToArray(), ref partInfo, false)) {continue;}break;case nameof(String):if (HEU_InputMeshUtility.SetMeshPointAttribute(session, inputNodeID, 0, fieldName,(values.Cast<string>()).ToArray(), ref partInfo)) {continue;}break;case nameof(GameObject):// Convert to resource file pathif (HEU_InputMeshUtility.SetMeshPointAttribute(session, inputNodeID, 0, fieldName,(values.Select(v => (AssetDatabase.GetAssetPath((GameObject)v)))).ToArray(), ref partInfo)) {continue;}break;}HEU_Logger.LogError(string.Format("Failed to set attribute {0}!", fieldName));return false;}break;}}if (!session.CommitGeo(inputNodeID)) {HEU_Logger.LogError("Filed to commit geo!");return false;}int parentId = HEU_HAPIUtility.GetParentNodeID(session, newNodeID);if (!session.CreateNode(parentId, "merge", null, false, out mergeNodeId)) {HEU_Logger.LogErrorFormat("Unable to create merge SOP node for connecting input assets.");return false;}if (!session.ConnectNodeInput(mergeNodeId, 0, newNodeID)) {HEU_Logger.LogErrorFormat("Unable to connect to input node!");return false;}if (!session.SetNodeDisplay(mergeNodeId, 1)) {HEU_Logger.LogWarningFormat("Unable to set display flag!");}inputNodeID = mergeNodeId;}else {bool bRes = _inputInterfaceMesh.CreateInputNodeWithDataUpload(session, connectNodeID, inputObject, out inputNodeID);if (!bRes) return false;//SetDetailStringAttribute(session, inputNodeID, "unity_tag",inputObject.tag);String groupName = inputObject.tag;SetPointGroup(session, inputNodeID, groupName);if (!session.CommitGeo(inputNodeID)) {HEU_Logger.LogError("Filed to commit geo!");return false;}}if (!session.CookNode(inputNodeID, false)) {HEU_Logger.LogError("New input node failed to cook!");return false;}return true;}private bool SetDetailStringAttribute(HEU_SessionBase session, int inputNodeID, string attributeName, string attributeValue) {HAPI_AttributeInfo attrInfo = new HAPI_AttributeInfo();attrInfo.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_DETAIL;attrInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_STRING;attrInfo.count = 1;attrInfo.tupleSize = 1;if (!session.AddAttribute(inputNodeID, 0, attributeName, ref attrInfo)|| !session.SetAttributeStringData(inputNodeID, 0, attributeName, ref attrInfo, new String[] { attributeValue }, 0, 1)) {HEU_Logger.LogError("Failed to add detail attribute.");return false;}return true;}private bool SetPointGroup(HEU_SessionBase session, int inputNodeID, string groupName) {HAPI_GeoInfo geoInfo = new HAPI_GeoInfo();if (session.GetGeoInfo(inputNodeID, ref geoInfo)) {for (int i = 0; i < geoInfo.partCount; i++) {HAPI_PartInfo partInfo = new HAPI_PartInfo();session.GetPartInfo(inputNodeID, i, ref partInfo);session.AddGroup(inputNodeID, i, HAPI_GroupType.HAPI_GROUPTYPE_POINT, groupName);int pointCount = partInfo.pointCount;int[] membership = new int[pointCount];for (int j = 0; j < pointCount; j++) {membership[j] = 1;}session.SetGroupMembership(inputNodeID, i, HAPI_GroupType.HAPI_GROUPTYPE_POINT, groupName, membership, 0, pointCount);}}else return false;return true;}private bool isDataTable(GameObject gameObject) {// judge if it is a subclass of the HEU_PDE_DataTableMonoBehaviour[] components = gameObject.GetComponents<MonoBehaviour>();Type baseGenericType = typeof(HEU_PDE_DataTable<>);foreach (MonoBehaviour component in components) {Type componentType = component.GetType();Type baseType = componentType.BaseType;if (baseType != null && baseType.IsGenericType && baseType.GetGenericTypeDefinition() == baseGenericType) {return true;}}return false;}public override bool IsThisInputObjectSupported(GameObject inputObject) {if (_inputInterfaceMesh.IsThisInputObjectSupported(inputObject)) return true;if (isDataTable(inputObject)) return true;return false;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/45276.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Unity】动态生成圆环体Mesh

代码由ChatGPT生成&#xff0c;后经人工调整。 /// <summary> /// 创建一个3维圆环体Mesh。 /// </summary> /// <param name"outerRadius">外半径。</param> /// <param name"innerRadius">内半径。</param> /// <…

关于vsCode中文插件突然无效的解决办法

今天今天github上下载了一个devtools 用vsCode打开,发现中文插件无效了 解决办法: 按ctrlshiftp 输入Configure Display Language 在弹出的语言中&#xff0c;选中zh-cn 然后重启vsCode

Android的EditText超出字数限制,给用户提示

Android的EditText超出字数限制&#xff0c;给用户提示 导语 如果项目着急使用&#xff0c;直接将下面代码复制到项目中&#xff0c;当做自定义的EditText使用就可以了。 建议将后面的解决思路看一遍&#xff0c;增强自己阅读源码的能力。 自定义的MaxLengthEditText /*** C…

最好理解的,用jeecms搭建一个新闻发布网站

1 前期环境配置 首先需要有jdk、tomcat和mysql&#xff0c;这里对于不同的jeecms版本对以上三种要求是不同的&#xff0c;我本人用的是jdk1.8&#xff0c;tomcat7,mysql5的版本。我们这里需要将从官网下载的压缩包解压出的ROOT文件放入tomcat下面的webapp下&#xff0c;替换掉…

一粒云之钉钉集成

一粒云dingtalk集成- 文章目录 一粒云dingtalk集成-1、一粒云管理后台配置步骤&#xff1a;2、钉钉管理后台配置步骤&#xff1a;2.1、自建应用2.3、填好对应的信息&#xff0c;下一步2.4、申请开通所有的权限——选择全部员工2.5、基础信息->查看详情&#xff0c;获得appke…

YLBs CAPTCHA - 签到题_N种花式签到,任你活动千万场,总有一款适合你

数字化时代&#xff0c;科技办会的理念正在逐步深入每个主办方的心里&#xff0c;如何给参会嘉宾带去好的参会体验&#xff1f;如何在众多的签到方式中找到适合自己活动的签到&#xff1f;31会议给你几款花样签到方式&#xff0c;让你的大会科技感十足。 二 / 微 / 码 / 签/ 到…

Ai配音专家 免费配置教程(适用于mac和windows系统)

Ai配音专家 语音转文字免费配置教程&#xff08;适用于mac和windows系统&#xff09; 推荐一款免费文本转语音的软件&#xff0c;文件来源于github&#xff0c;如果你在做自媒体的时候也不想用真音&#xff0c;那这款软件绝对适合你。配置过程分为以下内容&#xff1a; Ai配音…

vue前端使用Jenkins自动构建项目,保姆级教程

1. 开始前的准备工作 1台服务器&#xff0c;1个镜像仓库&#xff0c;安装docker 练习的话&#xff0c;服务器可以在[阿里云上](https://www.aliyun.com/?spm5176.ecscore_.top-nav.dlogo.509a4df5JhX1PN)领取一个月免费ECS云服务器&#xff0c;如下图在阿里云控台界面搜索容器…

vue 3.x 中使用ele-image时相对路径的图片加载失败

参考文档&#xff1a; https://element.eleme.cn/#/zh-CN/component/installation 环境: Mac OS X 10.12 [zcmele 2]$node -v v12.6.0 [zcmele 3]$npm -v 6.9.0 [zcmele 4]$cnpm -v cnpm6.1.0 (/usr/local/lib/node_modules/cnpm/lib/parse_argv.js) npm6.10.2 (/usr/local/li…

创意3D立体logo设计难不难?怎么设计?

本文由:“学设计上兔课网”原创,图片素材来自网络,仅供学习分享 创意3D立体logo设计难不难?怎么设计?虽然是3D的效果,但是我们也可以通过平面设计软件AI或者PS软件来实现这种伪3D的视觉效果。首先我们来看一看做完的最终效果 1.多边形工具,填充为0,有描边。利用多边形…

PR开场片头模板创意立体3D动态logo展示pr模板

&#xff0c; PR开场片头模板 创意立方体3Dlogo展示pr模板 这是一个整洁和动态动画的Premiere Pro模板&#xff0c;带有一个旋转立方体&#xff0c;时尚地旋转以显示您的媒体。包含1个标志占位符和1个文本占位符。简单介绍您的演示文稿&#xff0c;幻灯片&#xff0c;电视节目…

3D logo制作

3D制作图片 这次用AI来制作3Dlogo,首先把一张立体形状的logo图导入AI里 使用钢笔工具先把侧面白色部分抠下来 像上图一样抠下来之后在菜单里点击效果3D然后选择凸起和斜角,为了更好的去调整3D图形的变化,先点击预览调整凸出厚度数值为482pt,然后再去调整上面的方向环绕…

C4D暑期计划打卡7.30(2)

完成logo破碎小动画跟做 为完成的logo主体添加材质、增加天空、摄像机目标、对主体内部集进行单独材质添加&#xff0c;渲染增加景深&#xff0c;增添变化。 四视图 透视图 渲染图1 渲染图2

修改mars3d内置的文字

在使用mars3d开发中可能会需要修改内置的文字&#xff0c;如下图 mars3d内置的文字都会统一放在 mars3d.lang 这个对象下管理。如下图 如果需要修改&#xff0c;可以使用如下的方式 mars3d.Lang["_单击完成绘制"][0] "单击完成绘制&#xff0c;右键取消绘制&q…

CSS之 2D转换---3D转换(内含过渡)

转换可以实现元素的位移、旋转、缩放等效果 2D转换 translate --- 移动rotate --- 旋转scale --- 缩放 1.translate 语法&#xff1a;(px) transform:translate(x,y); transform:translateX(n); transform:translateY(n); 不会影响其他元素的位置 &#xff08;会变成前后…

chatgpt赋能python:Python的文件导出功能

Python的文件导出功能 作为一种流行的编程语言&#xff0c;Python 提供了广泛的文件导出功能&#xff0c;方便了开发者的日常工作。在本文中&#xff0c;我们将分享如何使用 Python 导出.py 文件&#xff0c;以及如何最大程度地利用这个功能。 什么是.py 文件&#xff1f; 首…

月薪2万,被新同事15秒气走。

今年&#xff0c;AIGC掀起了巨浪&#xff0c;身边不少人感到前所未有的焦虑&#xff1a; 朋友圈好友晒出的AI美图&#xff0c;仅需15秒&#xff0c;竟比我2周的设计更出色&#xff1b; 公司用AI写的文案&#xff0c;转化率提升了10%&#xff0c;可能要优化人员了; 职场危机提前…

AIGC制作的“视觉大片”走红!耗时仅3天,首批玩家吃到“红利”了

3月26日&#xff0c;2023山东省旅游发展大会在青岛拉开帷幕,当天&#xff0c;一条动画小视频惊艳了现场所有人&#xff0c;这条视频很快登上了“学习强国”、微博等社交媒体平台。视频名为《AI眼中的崂山四季》&#xff0c;108秒&#xff0c;呈现了青岛崂山大约十个特色“网红打…

Midjourney注册教程

Midjourney 太火了&#xff01;无论你是画师、设计师&#xff0c;还是淘宝电商等&#xff0c;都不得不熟悉并利用这种超级牛逼的 AI 绘图工具&#xff0c;不然真的保不定哪天就被淘汰了&#xff01; Midjourney 怎么玩&#xff1f;相信很多小白还不清楚&#xff01;这不巧了么…

2023年10个爆火的AI工具,分分钟提高工作质量!

大家好。我是不知名 设计师l1m0_&#xff0c;今天分享内容为&#xff1a;2023年10个爆火的AI工具。对AI感兴趣的朋友一定不能错过&#xff0c;一起来看看吧。 2023年&#xff0c;AIGC爆发式增长&#xff0c;各类AI软件随之应运而生&#xff0c;衍生出不少的设计行业AI黑科技 &a…