最近刚好在研究虚幻4的渲染流程,于是想把OBJ文件信息加载到虚幻4里面。
首先咋们先捋一下思路
第一: 既然我们要加载OBJ文件,那么我们就要知道OBJ里面到底存了些什么东西,我先在max里创建了一个简单的box然后导出成obj文件,然后用文本打开就会看到如下信息
# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware
# File Created: 04.12.2016 11:55:04
mtllib Box.mtl
#
# object Box001
#
v -37.4557 0.0000 37.1487
v -37.4557 0.0000 -37.1487
v 37.4557 0.0000 -37.1487
v 37.4557 0.0000 37.1487
v -37.4557 71.9826 37.1487
v 37.4557 71.9826 37.1487
v 37.4557 71.9826 -37.1487
v -37.4557 71.9826 -37.1487
# 8 vertices
vn 0.0000 -1.0000 -0.0000
vn 0.0000 1.0000 -0.0000
vn 0.0000 0.0000 1.0000
vn 1.0000 0.0000 -0.0000
vn 0.0000 0.0000 -1.0000
vn -1.0000 0.0000 -0.0000
# 6 vertex normals
vt 1.0000 0.0000 0.0000
vt 1.0000 1.0000 0.0000
vt 0.0000 1.0000 0.0000
vt 0.0000 0.0000 0.0000
# 4 texture coords
g Box001
usemtl wire_228214153
s 2
f 1/1/1 2/2/1 3/3/1 4/4/1
s 4
f 5/4/2 6/1/2 7/2/2 8/3/2
s 8
f 1/4/3 4/1/3 6/2/3 5/3/3
s 16
f 4/4/4 3/1/4 7/2/4 6/3/4
s 32
f 3/4/5 2/1/5 8/2/5 7/3/5
s 64
f 2/4/6 1/1/6 5/2/6 8/3/6
# 6 polygons
前几行#部分是一些创建信息什么的 每行v开头的就是顶点的信息啦 (X ,Y ,Z)。vn开头的是顶点法线方向 vt开头的是模型的uv坐标 最后f开头的是模型的indexbuffer信息绕序。
第二: 搞清楚了OBJ里面到底保存了啥之后我们下一步就是要把OBJ的信息读取到虚幻4里面才行啦,当然虚幻4这种强大的引擎当然有文件读取的方法啦。
FFileHelper:oadFileToString(LoadedString, *(FPaths::GameDir() + FilePathAndName + TEXT(".txt")));
这个函数就可以读取一个txt文件的信息。并把信息全部储存在一个Fstring里面。这里要注意了。如果txt文件里面的信息量超出了fstring的最大储存量是会出问题的。不过FString储存一个几万面的obj文件的信息还是没问题的。
第三:经过FFileHelper:oadFileToString(LoadedString, *(FPaths::GameDir() + FilePathAndName + TEXT(".txt")));函数处理后。OBJ文件信息会全部储存到Fstring里面,就我这段代码而言,txt文件的全部信息就储存到了(LoadedString里面。这个时候你可以通过蓝图的printstring或者c++的 addmessagetoscreen就能在游戏窗口里面看到打印信息了。
第四步:现在已经把OBJ文件信息加载进了虚幻。但是现在有两个问题。第一个问题就是,现在的信息是FString储存的一大串字符串信息,是原始的无法被我们直接使用,因为你可以清楚地看到这个字符串里面甚至还包含了#3d max 。。。。这些注释解释信息。我们需要把这一大串数据加工分类,把顶点信息这些数据提取出来然后保存到顶点数组里面,当然这个数组的数据类型必须是float什么的,不能是字符串类型。只有这样我们才能使用这些数据进行运算。而现在这些数据只是一大串字符。第二个问题,假设我们成功处理了那一大串字符串,并且把里面的顶点数据 法线数据 index绕序数据全部提取出来并且储存在了一个数组里面(缓冲区),之后我们要做的是如何在虚幻4里面用这些数据来绘制三维模型。
我们先来解决第一个问题,对Fstring里面的原始数据进行处理,让它变成能被我们使用的数据。
再来观察一下我们的obj文件,发现它都是一行一行地罗列顶点法线什么的信息的。所以我们可以对它进行切割。把它切成一行一行的Fstring数据。然后把每一行作为一个元素保存在一个FString的TArray里面
LoadedString.ParseIntoArrayLines(LineArray, true);
这样我们就得到了一个LineArray
我们访问LineArray里第一行 可以看到它的值是 # 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware。就是我们OBJ文件的第一行。也是LoadedString的第一行
现在我们成功将LoadedString以每一行切成一个小的FString并把这些小的FString保存在了LineArray里面
我访问LineArray保存顶点数据的一行 v -37.4557 0.0000 37.1487。但这个还不是我想要的。我想要里面的数字。所以我们可以再对这些FString再次进行切割。
LineArray[0].ParseIntoArray(PartsStringArray, TEXT(" "), true);
这样将一行字符串切成了4部分 第一部分是“v” 第二部分是“-37.4557” 第三部分是“0.0000” 第四部分是“37.1487”这样就成功拿到了数据。最后我们把FString转换成float即可。
用上面的方法,我提取出了TArray<FVector>Vertexbuffer TArray<FVector>Indexbuffer TArray<FVerctor>NormalArray TArray<Vector2D>uvArray
成功提取了资源之后我们就可以用上面的资源进行绘制了。
虚幻引擎里面有两个自定义模型组件 一个是custommeshcomponent 一个是ProcedureMeshComponent。CustomMeshComponent是没有UV的。所以我们使用ProcedureMeshComponent来绘制图形。为什么不像directX3d或者OpenGl那样直接绘制图形而是要借助一个组件呢。原因是ProcedureMeshComponent已经搭建好了一个自定义模型框架了。我们可以直接使用这个框架。如果你不想使用这个框架那么可以去看一下staticmeshcomponent的绘图流程。其实原理都是一样的。为了简便我这里使用现成的一个绘图框架来绘制
ProcedureMeshComponent里面有一个CreateMeshSection函数。我们把我们刚才提取到的资源了TArray<FVector>Vertexbuffer TArray<FVector>Indexbuffer TArray<FVerctor>NormalArray TArray<Vector2D>uvArray全部提交给这个函数就可以了。
这样就可以成功加载一个OBJ文件啦。
额打了这么多字手好累,去建个模型放松一下
|