美文网首页
Unreal Python 骨骼 Socket 自动化工具

Unreal Python 骨骼 Socket 自动化工具

作者: 智伤帝 | 来源:发表于2020-09-20 15:29 被阅读0次

    本文章转载自 智伤帝的个人博客 - 原文链接

    前言

      自动添加 Unreal 骨骼 Socket 的功能,我查了一下,发现第三方的 UnrealEnginePython 已经集成了这个功能。 github地址
      然而官方的插件在这方面还有很多限制。
      比如说官方的 Skeleton 类就根本没有相关的 Sockets 数组可以获取。 文档地址

      刚好最近收到了一个需求,需要实现通过 Excel 配置的文档批量自动生成对应骨骼的 Socket 效果。
      为了实现这个需求,还是跳不过调用 C++ 的 API ,不过这一次的操作可以借鉴 UnrealEnginePython 插件的实现方法。

    C++ 源码查询

      这个操作套路还是之前的套路,先通过 UI 显示的名称然后反向去查询源码的路径。
      如果右键菜单的名称不好找,可以去找它的 Tooltip , Tooltip 的名称比较长,比较唯一。

    image

      然后就可以通过 VScode 进行定位。

    image

      从这个 UI 命令中,可以找到 AddSocket 这个关键字命令。
      可以搜索一下这个命令,并且在 UI 命令的模块下可以找到相关联的脚本。

    image

      于是,按照我之前的经验。
      就可以想办法将这个类 FEditableSkeleton 引入的插件里面,然后就可以调用了。
      另外这个类是 F 开头的纯 C++ 类,因此这个类是无法作为蓝图的输入和输出类型的,只有继承自 UObject 的对象是可以暴露到 Python 里面。
      《大象无形》文档里面也有所提及。

    image

      同时这个 AddSocket 方法并不是静态方法,因此需要一些特殊的实例化操作,才可以使用。
      虚幻的实例化有好几种方法,不同的情况,用不同的方法,具体我也不清楚,但是作为工具人,这些源码功能肯定能在其他的源码里面找到答案。
      所以我就去搜索 FEditableSkeleton 这个类

    image

      首先排除了这个类本身的 cpp 文件和 头文件,剩下的使用参考已经非常清晰了。
      应该就是 SkeletonEditorModule.cpp 的实例化方案了。
      后面就是复制粘贴抄代码的事情。

    解决无法编译的问题

      然而经过我一通操作,将代码弄到我的蓝图里面之后,我却发现我居然无法通过编译。
      我测试了好多遍,都提示我这个调用方法有某些缺了头文件之类的,无法识别。
      我仔细核对了 build.cs 文件以及 C++ 引用的头文件,应该都没有什么缺失,于是我只好再尝试其他的方法。

      可能是我这个构造函数的操作方法不对,但是我看了搜索到的构造方法基本都需要 CreateEditableSkeleton 这个方法。
      于是我进一步沿着这个思路去解决它。

    image
    image

      于是我尝试用套这个构建方法,结果编译通过了~
      顺便到引擎测试一下是不是 Python 可以添加 Socket 了,然后可喜可贺,居然实现了。

    USkeletalMeshSocket* UPyToolkitBPLibrary::AddSkeletalMeshSocket(USkeleton* InSkeleton, FName InBoneName)
    {
        USkeletalMeshSocket* socket = nullptr;
    
        ISkeletonEditorModule& SkeletonEditorModule = FModuleManager::LoadModuleChecked<ISkeletonEditorModule>("SkeletonEditor");    
        TSharedRef<IEditableSkeleton> EditableSkeleton = SkeletonEditorModule.CreateEditableSkeleton(InSkeleton);    
        socket = EditableSkeleton->AddSocket(InBoneName);    
        return socket;
    }
    

    批量删除 Socket

      原本以为只要实现添加 Socket ,我的 Python 工具就万无一失了。
      但是考虑到如果使用者添加错了,删除 Socket 还要手动删除就很离谱。
      于是还得添加一个清空 Socket 的功能才行。

      然后我想直接套用我上面实现的 EditableSkeleton 的方法。
      然后才发现,原来上面调用的并不是 FEditableSkeleton 而是 IEditableSkeleton
      这两个有啥区别呢?《大象无形》里面没有提到 I 开头的代表啥。
      于是网上查了一下 naming convention (还好绑定没有白学~)

      然后总算找到了官方文档给出的定义 链接
      I 开头属于 abstract interfaces 抽象接口。

    image

      然后相应地去找 IEditableSkeleton 所在的脚本,其实这个时候可以发现这些脚本都在 SkeletonEditor 这个模块下。
      而且 FEditableSkeleton 在 Private 目录,而 IEditableSkeleton 在 Public 目录。

    image

      然而另外颇为诧异的是,IEditableSkeleton 没有删除 Socket 的相关函数,但是 FEditableSkeleton 里面有 HandleDeleteSockets 的函数。
      但是如果直接调用 FEditableSkeleton 根本无法通过编译。


      最后实在没办法了,查了 UnrealEnginePython 的插件也没有开窍,Unreal 的 C++ 学艺不精,只好找程序来支援一下。
      程序一看就说并不是所有的 API 可以暴露出来使用的,有些没有宏暴露的就不可以。
      于是我赶紧查了一下 C++ 的 API 文档,结果发现只能查到 IEditableSkeleton 这个类 链接
      SkeletonEditor 的 API 文档里面甚至没有提到 FEditableSkeleton(:з」∠)

      那现在该怎么办呢?
      程序说不慌,实在不行可以将 FEditableSkeleton 的功能代码抄到蓝图里面🤣


      我在仔细看了一下 HandleDeleteSockets 的代码内容,我突然就开窍了。

    image

      这个 Sockets.Remove 是如此的熟悉,这不就和 UnrealEnginePython 的 Python 操作一个样吗?
      于是我赶紧试验了一下传 Skeleton 的操作,果然将对应的 Socket Remove 删除掉就可以了~

      不过如果只是Remove操作无法在编辑器面板上更新数据,需要重开面板才能看到 Socket 的确被删除了。
      于是我结合上面的 IEditableSkeleton 进行更新就可以实现 Socket 删除的更新~

    void UPyToolkitBPLibrary::DeleteSkeletalMeshSocket(USkeleton* InSkeleton, TArray<USkeletalMeshSocket*> SocketList)    
    {
        InSkeleton->Modify();    
        for (USkeletalMeshSocket* Socket : SocketList)
        {
            InSkeleton->Sockets.Remove(Socket);    
        }
        ISkeletonEditorModule& SkeletonEditorModule = FModuleManager::LoadModuleChecked<ISkeletonEditorModule>("SkeletonEditor");    
        TSharedRef<IEditableSkeleton> EditableSkeleton = SkeletonEditorModule.CreateEditableSkeleton(InSkeleton);    
        EditableSkeleton->RefreshBoneTree();    
    }
    

    获取骨骼名称

      官方的 Python 可以获取到 Skeleton 的 bone_tree 信息。
      但是 BoneNode 就没有什么有价值的 API 可供调用了。
      查了一下 API 文档,原本是可以通过 BoneNode 获取骨骼名称,但是相关方法已经 Deprecated 了

      于是我又参考了 UnrealEnginePython 插件。
      可以通过 USkeleton 获取骨骼的数量和骨骼的名称。

    int32 UPyToolkitBPLibrary::GetSkeletonBoneNum(USkeleton* InSkeleton)
    {
        return InSkeleton->GetReferenceSkeleton().GetNum();    
    }
    
    FName UPyToolkitBPLibrary::GetSkeletonBoneName(USkeleton* InSkeleton,int32 BoneIndex)
    {
        return InSkeleton->GetReferenceSkeleton().GetBoneName(BoneIndex);    
    }
    

      这样 Socket 的增删操作就完场了,改和查的操作可以通过 SkeletalMesh的 API 实现。

    Python 结合 CSV 模块编写插件界面

      后续需要开发一个 CSV 编辑界面,这样可以打通 Excel 文档同时又兼有 文件简单的特点。
      这次尝试使用 dayu_widgets 来实现效果。
      dayu_widgets 封装了一系列 MVC 框架相关的类。
      可以直接调用起来,具体可以参考 dayu_widgets 的 example 链接

      相关功能已经集成到了 PyToolkit 仓库里面。

    image

    总结

      这次重新整理了一波 C++ 扩展的开发思路,没有深入搞过 Unreal C++ ,总结就一个字 菜(:з」∠)
      只能说上面那些套路算是一种野生的解决方案,可以快速应付项目需求,但是真正要摸透还是得用 Unreal 开发几个 C++ 游戏才行~

    相关文章

      网友评论

          本文标题:Unreal Python 骨骼 Socket 自动化工具

          本文链接:https://www.haomeiwen.com/subject/tbfpyktx.html