UE4 实时读取模型数据插件

UE4 2018-07-22

在Runtime模式下读取模型数据,以前做家装时候有出现过这种需求,看现在一些论坛上就是放个视频给很多人眼馋一下,本身传承知识的习惯,博主最近抽空做了个可以实时读取,也可以点击读取的插件,同样的先说下原理和实现,最后放上插件源码。

这个插件照样是使用UE4.19,好了废话不说了。

插件的实现主要有2个函数,如下所示:

	UFUNCTION(BlueprintCallable,Category="MeshLoader")
	static FReturnedData LoadMesh(FString filepath,EPathType type= EPathType:: Absolute);

	UFUNCTION(BlueprintCallable, Category = "MeshLoader")
	static TArray<FString> GetAllFilesInDirectory(const FString directory, const bool fullPath, const bool withoutExtention, const FString onlyFilesStartingWith, const FString onlyFilesWithExtension);

这两个一个用来读取当前模型顶点,一个用来获取某各路径下的所有文件。

读取模型数据,插件使用了assimpSDK,assimp是一个加载模型数据的库,可以提取模型的定点数据、法线、纹理坐标,assimp的数据会存为一个包,这个包的数据拥有一个比较复杂的数据结构,像Mesh的结构会储存Vertices、Normals、TextureCoords、Faces等。

存储的这些数据,都是以数组方式存在,那么问题来了,怎么去还原这个数据,之前我们的另一个插件Metaballs是用ProceduralMesh实现,那么这里同样是使用ProceduralMesh+CreateMeshSection去还原通过assimp存储的模型数据。

FindMeshInfo函数,是通过assimp创建的结构数据,assimp存储会以结构方式进行,最上面是scene,然后就像脑图一样,有Mesh,有Material等等。所以这里的mesh、mi是将模型数据,存入vertex、mTransformation、uv,可以看到全都是将对应的aiMesh *mesh中去提取Vector、Normal、UV、Tangent等等数据,这些数据都保存在meshInfo里,也就是FMeshInfo &mi = result.meshInfo[meshidx];中的mi,meshInfo其实是个结构体,他里面包含的数据,就是通过assimp获取的模型数据。

然后再来说LoadMesh,LoadMesh里其实没有太多东西,因为数据结构是在FindMeshInfo里已经完成的,所以LoadMesh里一个是查找路径,一个是将meshInfo添加到当前函数,路径的话其实UE4有自己的API,叫FPaths,里面有各种Dir,你可以弄成自己想要的Dir,可以是引擎的Engine目录,也可以是项目的Content目录,或者工程目录,具体可以看FPaths里面的方法,FPaths::ProjectContentDir()很好理解就是项目的Content目录,mScenePtr是用来读取当前的模型文件,然后FindMesh再去根据上面图中的索引路径去查询每个节点数据。

如果是自定义路径,可以使用GetBaseFilename方法。

剩下一个函数GetAllFilesInDirectory就是用来获取目录下所有文件了,这里文件不限制后缀格式,所以使用这个节点可以获取任何类型的对象,图片,xml,反正就是各种数据,你可以自己写个解析xml的配合这个节点来用,也可以写个解析XXX的配合GetAllFilesInDirectory来用。

那么这个节点很好理解,首先获取一个路径,然后遍历路径下的文件,IPlatformFile是UE自带的API,可以用来对文件对象进行操作,方法包含了文件I/O,读取当前平台路径,获取当前文件名字,获取当前文件,获取当前磁盘上一个文件名字,反正具体去看IPlatformFile这个类好了,这里使用了一个GetExtension用来取指定后缀的文件,属于FPaths中的方法,具体可以定义到GetExtension索引,剩下的其实就没有什么了,最后IF里套了一个三元运算符来看GetExtension下的withoutExtention布尔变量是否是自定义路径还是返回一个文件名。

然后来看UE里的实现,首先是生成Mesh,既然是ProceduralMesh,所以需要一个ProceduralMesh组件,然后LoadMesh的逻辑主要是这样的,靠的是LoadMesh节点:

这里用的函数,我的思路是这样的,首先UMG里面用按钮点一下,通过GetAllFilesInDirectory获取路径和文件,然后将路径文件传入这个LoadMeshF函数里,点击函数如下图所示:

上述方法就是通过GetAllFilesInDirectory函数获取路径,这是个String数组,然后遍历一下获取所有该路径下的文件,只查找后缀为FBX的,然后这里有个跨UMG传输数据,我以前讲的一个文章里有这种实现,链接:https://ericsong.org/2017/10/2416.html,ScrollBox是一个下拉滚动条,如下图所示:

这个就是UI了,方框里的数据,是通过CreateWidget去Add到这个容器里的,创建的另一个UMG是个button,如下图所示:

这个button的逻辑如下图所示:

调用LoadMeshF那个Actor蓝图里面的函数,FilePath是在主UMG中,传入的FilePath路径,如下图所示:

然后GetAllFilesInDirectory的path变量填写你的电脑绝对路径,最后运行游戏就是如下图所示:

上面视频是实时读取,你可以在主UMG中,断开Tick,把下面的OnClick连接上:

好了,最后附上整个工程,注意了默认运行是没有FBX的,你需要在UMG函数里这个节点,添加你自己的路径,比如C:/test,然后再这个文件夹下放几个FBX或者OBJ文件:

还有一个问题,材质的赋予,到FBX那个Actor蓝图里,的LoadMeshF函数,我目前就只给了所有ProceduralMesh一样的材质,你可以根据路径文件的Index,分别给予不同的材质。

最后附上工程,工程里面的Plugins是插件,带插件源码,请使用UE4.19打开:

链接:https://pan.baidu.com/s/1kXQcJErCw-_6MKqM0AqctA 密码:aiab

评论 (34)
  • 小宁

    大神,打包出来后提示找不到assimp-vc140-mt.dll,有方法解决吗?

    回复
    • K

      帅哥你有解决吗 我也不行

      回复
    • 未来很美

      解决了吗,遇到同样的问题

      回复
    • Luison

      我有,需要的请ping我

      回复
  • 嘿嘿嘿

    老哥哥,为毛打包出来就报错。。只要用到LoadMehs就打包出来会报错

    回复
    • Eric Song

      把那个DLL也带进去

      回复
  • 嘻嘻嘻

    是打包后放到win64下面吗? 我试过了 并不行哈

    回复
    • Eric Song

      不是,在你的C++工程里,把DLL添加进去,可以用if (Target.Platform == UnrealTargetPlatform.Win64)
      {
      RuntimeDependencies.Add(new RuntimeDependency(Path.Combine(“YOUR PATH”, “YOUR DLL.dll”)));
      }
      也可以用C++默认添加LIB的方式

      回复
  • Lee

    老哥 不行啊 如果FBX是多个材质就坏了

    回复
    • Eric Song

      多个材质修改蓝图指定不同材质的index,或者拓展插件

      回复
  • Eric Su

    老哥问一下 现在有个需求 是需要实时的加载一个格式为DEM高程数据的地形文件到UE4的场景中 有什们思路或者解决方案可以指点一下吗

    回复
    • Eric Song

      emm,这个插件实现的方法主要是基于一个第三方的SDK,这个库支持三维模型的数据格式,DEM的话,你看看有没有对应的这种第三方库可以读取这种格式的,思路都一样。

      回复
  • Al3ix

    Assimp::Importer mImporter;

    const aiScene* mScenePtr = mImporter.ReadFile(file, aiProcess_Triangulate | aiProcess_MakeLeftHanded | aiProcess_CalcTangentSpace | aiProcess_GenSmoothNormals | aiProcess_OptimizeMeshes);

    mScenePtr 为空

    回复
    • Eric Song

      emm这是怎么出来的

      回复
  • test_test

    您好 我打包之后没有报错,但是加载模型的功能实现不了,您知道是什么原因吗

    回复
    • Eric Song

      好像之前评论有人说过,我忘了怎么回复了。你试试找一下打包引入插件的文章看下,我要找到之前回复谁的话发给你

      回复
    • 未来很美

      您好,找到了吗,我也遇到类似问题

      回复
  • Wilson

    老哥,这插件是不支持打包到移动端的吗?

    回复
    • Eric Song

      emmm,移动端没试过啊

      回复
  • 未来很美

    大牛,如何默认将所有的模型都显示出来呢,我试了只能显示文件中的最后一个模型

    回复
    • Eric Song

      默认是全部显示所有模型的啊,你看下那个DEMO工程里的例子

      回复
    • 未来很美

      我直接运行了你的demo,模型按钮全部创建出来了,但是需要点击一个按钮场景中才出现对应的模型,我想所有的按钮和模型都直接显示出来。
      另外我在UE4编辑窗口下运行demo正常,但是打包后点击加载模型无反应,希望大牛能给指点一下。是不是Developer和Runtime的区别,需要怎么处理呢?

      回复
    • Eric Song

      DEMO里有个tick方式,你可以断开button去连tick方式

      回复
    • 未来很美

      tick方式我也试过了,场景中只能加载显示出一个模型。切换点击模型按钮能显示不同的,但是只能显示一个。

      回复
    • Eric Song

      蓝图对象里把程序化组建重新做一个,和插件里的一一对应。插件里读取几个FBX就在蓝图对象里创建几个mesh

      回复
    • 未来很美

      这个动态加载能不能实现异步加载,模型多的时候会卡

      回复
  • knoxcgh

    大佬,您的工程读复杂模型只能显示部分模型 有解决吗

    回复
    • Eric Song

      我想可能是因为最后用UEProceduralMesh还原出了问题,抱歉这个可能一时半会只能先拆分复杂模型做一下了。

      回复
  • 未来很美

    你好,添加进来的模型如何加点击事件呢?

    回复
    • Eric Song

      和以前方法一下,type,检索mesh,检索名字等等

      回复
    • 甄德帅

      onClick事件没有反应,鼠标射线也获取不到,我应该怎么给他加上事件….跪求大佬指点

      回复
  • 6666

    421版本无法运行,有办法解决吗?

    回复
  • bgm17t

    请教dalao,我使用您的这个源文件无法读取出模型,左侧的框里已经有了读取出来的FBX文件,但是点击FBX文件没有任何反应,也没有FBX模型生成。我打开C++文件看到ObjectMacros.h、ScriptMacros.h、ProceduralMeshComponent.h、Kismet/BlueprintFunctionLibrary.h都无法打开源文件。UE4的刷新Visual Studio功能也无法使用。

    回复
  • Luison

    大神,终于找到你啦。从github到unreal的论坛,在这里找到你,不容易啊,o(╥﹏╥)o。非常感谢您的插件,有个问题,有没有办法在读取mesh的时候,把纹理也加载进去呢,都作为漫反射纹理加载进去
    当前的实现,如果加载一个多模型物体(单个obj里包括多个模块),set material只会应用到第一个模块上面

    回复
Top