/
FbxModelLoader.cpp
149 lines (115 loc) · 4.67 KB
/
FbxModelLoader.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include "FbxModelLoader.h"
#include <istream>
#include "openfbx/ofbx.h"
#include "os/path.h"
#include "string/case_conv.h"
#include "stream/ScopedArchiveBuffer.h"
#include "FbxSurface.h"
#include "../StaticModel.h"
#include "../StaticModelSurface.h"
namespace model
{
FbxModelLoader::FbxModelLoader() :
ModelImporterBase("FBX")
{}
namespace
{
inline MeshVertex ConstructMeshVertex(const ofbx::Geometry& geometry, int index)
{
auto vertices = geometry.getVertices();
auto normals = geometry.getNormals();
auto uvs = geometry.getUVs();
auto colours = geometry.getColors();
return MeshVertex(
Vertex3(vertices[index].x, vertices[index].y, vertices[index].z),
normals != nullptr ? Normal3(normals[index].x, normals[index].y, normals[index].z) : Normal3(1, 0, 0),
uvs != nullptr ? TexCoord2f(uvs[index].x, 1.0 - uvs[index].y) : TexCoord2f(0, 0), // invert v
colours != nullptr ? Vector3(colours[index].x, colours[index].y, colours[index].z) : Vector3(1, 1, 1)
);
}
}
IModelPtr FbxModelLoader::loadModelFromPath(const std::string& path)
{
// Open an ArchiveFile to load
auto file = path_is_absolute(path.c_str()) ?
GlobalFileSystem().openFileInAbsolutePath(path) :
GlobalFileSystem().openFile(path);
if (!file)
{
rError() << "Failed to load model " << path << std::endl;
return IModelPtr();
}
// Load the model data from the given stream
archive::ScopedArchiveBuffer data(*file);
auto scene = ofbx::load(static_cast<ofbx::u8*>(data.buffer),
static_cast<int>(data.length), (ofbx::u64)ofbx::LoadFlags::TRIANGULATE);
if (!scene)
{
rError() << "Failed to load FBX model " << path << std::endl;
return IModelPtr();
}
std::vector<FbxSurface> surfaces;
for (int meshIndex = 0; meshIndex < scene->getMeshCount(); ++meshIndex)
{
auto mesh = scene->getMesh(meshIndex);
auto geometry = mesh->getGeometry();
// Assign the materials for each surface
for (int m = 0; m < mesh->getMaterialCount(); ++m)
{
auto material = mesh->getMaterial(m);
surfaces.emplace_back().setMaterial(material->name);
}
if (surfaces.empty())
{
surfaces.emplace_back().setMaterial("Material"); // create at least one surface
}
auto materials = geometry->getMaterials();
auto faceIndices = geometry->getFaceIndices();
for (int i = 0; i < geometry->getIndexCount(); i += 3)
{
// Material index is assigned per triangle
auto polyIndex = i / 3;
auto materialIndex = materials ? materials[polyIndex] : 0; // put into first material by default
// Reverse the poly indices to get the CCW order
auto indexA = (faceIndices[i + 2] * -1) - 1; // last index is negative and 1-based
auto indexB = faceIndices[i + 1];
auto indexC = faceIndices[i + 0];
auto& surface = surfaces[materialIndex];
surface.addVertex(ConstructMeshVertex(*geometry, indexA));
surface.addVertex(ConstructMeshVertex(*geometry, indexB));
surface.addVertex(ConstructMeshVertex(*geometry, indexC));
}
// Apply the global transformation matrix
auto t = geometry->getGlobalTransform();
#if 0
auto transform = Matrix4::byColumns(
t.m[0], t.m[1], t.m[2], t.m[3],
t.m[4], t.m[5], t.m[6], t.m[7],
t.m[8], t.m[9], t.m[10], t.m[11],
t.m[12], t.m[13], t.m[14], t.m[15]
);
#endif
// "Objects in the FBX SDK are always created in the right handed, Y-Up axis system"
auto transform = Matrix4::getIdentity();
if (scene->getGlobalSettings()->UpAxis == ofbx::UpVector_AxisY)
{
transform = transform.getPremultipliedBy(Matrix4::getRotationForEulerXYZDegrees(Vector3(90, 0, 0)));
}
}
// Construct a set of static surfaces from the FBX surfaces, destroying them on the go
std::vector<StaticModelSurfacePtr> staticSurfaces;
for (auto& fbxSurface : surfaces)
{
auto& staticSurface = staticSurfaces.emplace_back(std::make_shared<StaticModelSurface>(
std::move(fbxSurface.getVertexArray()), std::move(fbxSurface.getIndexArray())));
staticSurface->setDefaultMaterial(fbxSurface.getMaterial());
staticSurface->setActiveMaterial(staticSurface->getDefaultMaterial());
}
surfaces.clear();
auto staticModel = std::make_shared<StaticModel>(staticSurfaces);
// Set the filename
staticModel->setFilename(os::getFilename(file->getName()));
staticModel->setModelPath(path);
return staticModel;
}
}