WoW Model Viewer
Your premiere tool for viewing, equipping and animating World of Warcraft models.
Loading...
Searching...
No Matches
FBXHeaders.cpp
Go to the documentation of this file.
1/*----------------------------------------------------------------------*\
2| This file is part of WoW Model Viewer |
3| |
4| WoW Model Viewer is free software: you can redistribute it and/or |
5| modify it under the terms of the GNU General Public License as |
6| published by the Free Software Foundation, either version 3 of the |
7| License, or (at your option) any later version. |
8| |
9| WoW Model Viewer is distributed in the hope that it will be useful, |
10| but WITHOUT ANY WARRANTY; without even the implied warranty of |
11| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12| GNU General Public License for more details. |
13| |
14| You should have received a copy of the GNU General Public License |
15| along with WoW Model Viewer. |
16| If not, see <http://www.gnu.org/licenses/>. |
17\*----------------------------------------------------------------------*/
18
19/*
20 * FBXHeaders.cpp
21 *
22 * Created on: 14 may 2019
23 * Copyright: 2019 , WoW Model Viewer (http://wowmodelviewer.net)
24 */
25
26#include "FBXHeaders.h"
27
28#include "fbxsdk.h"
29#include "glm/gtc/quaternion.hpp"
30#include "glm/gtc/matrix_transform.hpp"
31#include "glm/gtx/quaternion.hpp"
32#include "glm/gtx/transform.hpp"
33
34#include "FBXAnimExporter.h"
35#include "ModelRenderPass.h"
36#include "WoWModel.h"
37
38bool FBXHeaders::createFBXHeaders(FbxString fileVersion, std::string l_FileName, FbxManager* & l_Manager,
39 FbxExporter* & l_Exporter, FbxScene* & l_Scene)
40{
41 //LOG_INFO << "Building FBX Header...";
42
43 // Create an exporter.
44 l_Exporter = nullptr;
45 l_Exporter = FbxExporter::Create(l_Manager, "");
46
47 if (!l_Exporter->Initialize(l_FileName.c_str(), -1, l_Manager->GetIOSettings()))
48 {
49 LOG_ERROR << "Unable to create the FBX SDK exporter";
50 return false;
51 }
52 //LOG_INFO << "FBX SDK exporter successfully created";
53
54 // make file compatible with older fbx versions
55 l_Exporter->SetFileExportVersion(fileVersion);
56
57 l_Scene = FbxScene::Create(l_Manager, "My Scene");
58 if (!l_Scene)
59 {
60 LOG_ERROR << "Unable to create FBX scene";
61 return false;
62 }
63
64 // convert scene from Yup to Zup
65 const FbxAxisSystem conv(FbxAxisSystem::eMayaZUp); // we desire to convert the scene from Y-Up to Z-Up
66 conv.ConvertScene(l_Scene);
67
68 //LOG_INFO << "FBX SDK scene successfully created";
69 return true;
70}
71
72// Create mesh.
73FbxNode* FBXHeaders::createMesh(FbxManager* & l_manager, FbxScene* & l_scene, WoWModel* model, const glm::mat4& matrix,
74 const glm::vec3& offset)
75{
76 // Create a node for the mesh.
77 std::string meshNodeName = model->name();
78 auto slashPos = meshNodeName.rfind('/');
79 if (slashPos != std::string::npos)
80 meshNodeName = meshNodeName.substr(slashPos + 1);
81 FbxNode* meshNode = FbxNode::Create(l_manager, meshNodeName.c_str());
82
83 // Create new Matrix Data
84 const auto m = glm::scale(glm::vec3(matrix[0][0], matrix[1][1], matrix[2][2]));
85
86 // Create mesh.
87 const auto num_of_vertices = model->origVertices.size();
88 FbxMesh* mesh = FbxMesh::Create(
89 l_manager, meshNodeName.c_str());
90 mesh->InitControlPoints(static_cast<int>(num_of_vertices));
91 FbxVector4* vertices = mesh->GetControlPoints();
92
93 // Set the normals on Layer 0.
94 auto layer = mesh->GetLayer(0);
95 if (layer == nullptr)
96 {
97 mesh->CreateLayer();
98 layer = mesh->GetLayer(0);
99 }
100
101 // We want to have one normal for each vertex (or control point),
102 // so we set the mapping mode to eBY_CONTROL_POINT.
103 FbxLayerElementNormal* layer_normal = FbxLayerElementNormal::Create(mesh, "");
104 layer_normal->SetMappingMode(FbxLayerElement::eByControlPoint);
105 layer_normal->SetReferenceMode(FbxLayerElement::eDirect);
106
107 // Create UV for Diffuse channel.
108 FbxLayerElementUV* layer_texcoord = FbxLayerElementUV::Create(mesh, "DiffuseUV");
109 layer_texcoord->SetMappingMode(FbxLayerElement::eByControlPoint);
110 layer_texcoord->SetReferenceMode(FbxLayerElement::eDirect);
111 layer->SetUVs(layer_texcoord, FbxLayerElement::eTextureDiffuse);
112
113 // Fill data.
114 LOG_INFO << "Adding main mesh Verts...";
115 for (size_t i = 0; i < num_of_vertices; i++)
116 {
117 ModelVertex& v = model->origVertices[i];
118 const glm::vec3 Position = glm::vec3(m * glm::vec4((v.pos + offset), 1.0f));
119 vertices[i].Set(Position.x * SCALE_FACTOR, Position.y * SCALE_FACTOR, Position.z * SCALE_FACTOR);
120 const glm::vec3 vn = glm::normalize(v.normal);
121 layer_normal->GetDirectArray().Add(FbxVector4(vn.x, vn.y, vn.z));
122 layer_texcoord->GetDirectArray().Add(FbxVector2(v.texcoords.x, 1.0 - v.texcoords.y));
123 }
124
125 // Create polygons.
126 const size_t num_of_passes = model->passes.size();
127 FbxLayerElementMaterial* layer_material = FbxLayerElementMaterial::Create(mesh, "");
128 layer_material->SetMappingMode(FbxLayerElement::eByPolygon);
129 layer_material->SetReferenceMode(FbxLayerElement::eIndexToDirect);
130 layer->SetMaterials(layer_material);
131
132 int mtrl_index = 0;
133 LOG_INFO << "Setting main mesh Polys...";
134 for (size_t i = 0; i < num_of_passes; i++)
135 {
136 ModelRenderPass* p = model->passes[i];
137 if (p->init())
138 {
139 // Build material name.
140 FbxString mtrl_name = "testToChange";
141 mtrl_name.Append("_", 1);
142 char tmp[32];
143 _itoa(static_cast<int>(i), tmp, 10);
144 mtrl_name.Append(tmp, strlen(tmp));
145 FbxSurfaceMaterial* material = l_scene->GetMaterial(mtrl_name.Buffer());
146 meshNode->AddMaterial(material);
147
148 const ModelGeosetHD* g = model->geosets[p->geoIndex];
149 const size_t num_of_faces = g->icount / 3;
150 for (size_t j = 0; j < num_of_faces; j++)
151 {
152 mesh->BeginPolygon(mtrl_index);
153 mesh->AddPolygon(model->indices[g->istart + j * 3]);
154 mesh->AddPolygon(model->indices[g->istart + j * 3 + 1]);
155 mesh->AddPolygon(model->indices[g->istart + j * 3 + 2]);
156 mesh->EndPolygon();
157 }
158
159 mtrl_index++;
160 }
161 }
162
163 layer->SetNormals(layer_normal);
164
165 const FbxGeometryConverter lGeometryConverter(l_manager);
166 lGeometryConverter.ComputeEdgeSmoothingFromNormals(mesh);
167 //convert soft/hard edge info to smoothing group info
168 lGeometryConverter.ComputePolygonSmoothingFromEdgeSmoothing(mesh);
169
170 // Set the mesh as the node attribute of the node.
171 meshNode->SetNodeAttribute(mesh);
172
173 // Set the shading mode to view texture.
174 meshNode->SetShadingMode(FbxNode::eTextureShading);
175
176 return meshNode;
177}
178
179void FBXHeaders::createSkeleton(WoWModel* l_model, FbxScene*& l_scene, FbxNode*& l_skeletonNode,
180 std::map<int, FbxNode*>& l_boneNodes)
181{
182 std::string skelName = l_model->name();
183 auto skelSlashPos = skelName.rfind('/');
184 if (skelSlashPos != std::string::npos)
185 skelName = skelName.substr(skelSlashPos + 1);
186 skelName += "_rig";
187 l_skeletonNode = FbxNode::Create(
188 l_scene, skelName.c_str());
189 FbxSkeleton* bone_group_skeleton_attribute = FbxSkeleton::Create(l_scene, "");
190 bone_group_skeleton_attribute->SetSkeletonType(FbxSkeleton::eRoot);
191 bone_group_skeleton_attribute->Size.Set(10.0 * SCALE_FACTOR);
192 l_skeletonNode->SetNodeAttribute(bone_group_skeleton_attribute);
193
194 std::vector<FbxSkeleton::EType> bone_types;
195 const size_t num_of_bones = l_model->bones.size();
196
197 // Set bone type.
198 std::vector<bool> has_children;
199 has_children.resize(num_of_bones);
200 for (size_t i = 0; i < num_of_bones; ++i)
201 {
202 const Bone bone = l_model->bones[i];
203 if (bone.parent != -1)
204 has_children[bone.parent] = true;
205 }
206
207 bone_types.resize(num_of_bones);
208 for (size_t i = 0; i < num_of_bones; ++i)
209 {
210 const Bone bone = l_model->bones[i];
211
212 if (bone.parent == -1)
213 {
214 bone_types[i] = FbxSkeleton::eRoot;
215 }
216 else if (has_children[i])
217 {
218 bone_types[i] = FbxSkeleton::eLimb;
219 }
220 else
221 {
222 bone_types[i] = FbxSkeleton::eLimbNode;
223 }
224 }
225
226 // Create bone.
227 for (size_t i = 0; i < num_of_bones; ++i)
228 {
229 const Bone& bone = l_model->bones[i];
230 glm::vec3 trans = bone.pivot;
231
232 int pid = bone.parent;
233 if (pid > -1)
234 trans -= l_model->bones[pid].pivot;
235
236 FbxString bone_name("bone_");
237 bone_name += static_cast<int>(i);
238
239 FbxNode* skeleton_node = FbxNode::Create(l_scene, bone_name);
240 l_boneNodes[i] = skeleton_node;
241 skeleton_node->LclTranslation.Set(FbxVector4(trans.x * SCALE_FACTOR, trans.y * SCALE_FACTOR,
242 trans.z * SCALE_FACTOR));
243
244 FbxSkeleton* skeleton_attribute = FbxSkeleton::Create(l_scene, bone_name);
245 skeleton_attribute->SetSkeletonType(bone_types[i]);
246
247 if (bone_types[i] == FbxSkeleton::eRoot)
248 {
249 skeleton_attribute->Size.Set(10.0 * SCALE_FACTOR);
250 l_skeletonNode->AddChild(skeleton_node);
251 }
252 else if (bone_types[i] == FbxSkeleton::eLimb)
253 {
254 skeleton_attribute->LimbLength.Set(
255 5.0 * SCALE_FACTOR * (sqrtf(trans.x * trans.x + trans.y * trans.y + trans.z * trans.z)));
256 l_boneNodes[pid]->AddChild(skeleton_node);
257 }
258 else
259 {
260 skeleton_attribute->Size.Set(1.0 * SCALE_FACTOR);
261 l_boneNodes[pid]->AddChild(skeleton_node);
262 }
263
264 skeleton_node->SetNodeAttribute(skeleton_attribute);
265 }
266}
267
268void FBXHeaders::storeBindPose(FbxScene* & l_scene, std::vector<FbxCluster*> l_boneClusters, FbxNode* l_meshNode)
269{
270 FbxPose* pose = FbxPose::Create(l_scene, "Bind Pose");
271 pose->SetIsBindPose(true);
272
273 for (const auto it : l_boneClusters)
274 {
275 FbxNode* node = it->GetLink();
276 FbxMatrix matrix = node->EvaluateGlobalTransform();
277 pose->Add(node, matrix);
278 }
279
280 pose->Add(l_meshNode, l_meshNode->EvaluateGlobalTransform());
281
282 l_scene->AddPose(pose);
283}
284
285/* Not ready yet...
286void FBXHeaders::storeRestPose(FbxScene* & l_scene, FbxNode* & l_SkeletonRoot)
287{
288 if (l_SkeletonRoot == nullptr)
289 return;
290
291 FbxString lNodeName;
292 FbxNode* lKFbxNode;
293 FbxMatrix lTransformMatrix;
294 FbxVector4 lT, lR, lS(1.0, 1.0, 1.0);
295
296 // Create the rest pose
297 FbxPose* pose = FbxPose::Create(l_scene, "Rest Pose");
298
299 // Set the skeleton root node to the global position (10, 10, 10)
300 // and global rotation of 45deg along the Z axis.
301 lT.Set(10.0, 10.0, 10.0);
302 lR.Set(0.0, 0.0, 45.0);
303
304 lTransformMatrix.SetTRS(lT, lR, lS);
305
306 // Add the skeleton root node to the pose
307 lKFbxNode = l_SkeletonRoot;
308 pose->Add(lKFbxNode, lTransformMatrix, false /*it's a global matrix);
309
310 // Set the lLimbNode1 node to the local position of (0, 40, 0)
311 // and local rotation of -90deg along the Z axis. This show that
312 // you can mix local and global coordinates in a rest pose.
313 lT.Set(0.0, 40.0, 0.0);
314 lR.Set(0.0, 0.0, -90.0);
315 lTransformMatrix.SetTRS(lT, lR, lS);
316
317 // Add the skeleton second node to the pose
318 lKFbxNode = lKFbxNode->GetChild(0);
319 pose->Add(lKFbxNode, lTransformMatrix, true /*it's a local matrix);
320
321 // Set the lLimbNode2 node to the local position of (0, 40, 0)
322 // and local rotation of 45deg along the Z axis.
323 lT.Set(0.0, 40.0, 0.0);
324 lR.Set(0.0, 0.0, 45.0);
325 lTransformMatrix.SetTRS(lT, lR, lS);
326
327 // Add the skeleton second node to the pose
328 lKFbxNode = lKFbxNode->GetChild(0);
329 lNodeName = lKFbxNode->GetName();
330 pose->Add(lKFbxNode, lTransformMatrix, true /*it's a local matrix);
331
332 // Now add the pose to the scene
333 l_scene->AddPose(pose);
334}*/
335
336void FBXHeaders::createAnimation(WoWModel* l_model, FbxScene*& l_scene, std::string animName, ModelAnimation cur_anim,
337 std::map<int, FbxNode*>& skeleton)
338{
339 if (skeleton.empty())
340 {
341 LOG_ERROR << "No bones in skeleton, so animation will not be exported";
342 return;
343 }
344
345 // Animation stack and layer.
346 FbxAnimStack* anim_stack = FbxAnimStack::Create(l_scene, animName.c_str());
347 FbxAnimLayer* anim_layer = FbxAnimLayer::Create(l_scene, animName.c_str());
348 anim_stack->AddMember(anim_layer);
349
350 //LOG_INFO << "Animation length:" << cur_anim.length;
351 float timeInc = static_cast<float>(cur_anim.length) / 60.0f;
352 if (timeInc < 1.0f)
353 {
354 timeInc = static_cast<float>(cur_anim.length);
355 }
356 FbxTime::SetGlobalTimeMode(FbxTime::eFrames60);
357 //LOG_INFO << "Skeleton Bone count:" << skeleton.size();
358
359 //LOG_INFO << "Starting frame loop...";
360 for (uint32 t = 0; t < cur_anim.length; t += timeInc)
361 {
362 //LOG_INFO << "Starting frame" << t;
363 FbxTime time;
364 time.SetSecondDouble(static_cast<float>(t) / 1000.0);
365
366 for (auto& it : skeleton)
367 {
368 int b = it.first;
369 Bone& bone = l_model->bones[b];
370
371 bool rot = bone.rot.uses(cur_anim.Index);
372 bool scale = bone.scale.uses(cur_anim.Index);
373 bool trans = bone.trans.uses(cur_anim.Index);
374
375 if (!rot && !scale && !trans) // bone is not animated, skip it
376 continue;
377
378 if (trans)
379 {
380 FbxAnimCurve* t_curve_x = skeleton[b]->LclTranslation.GetCurve(
381 anim_layer, FBXSDK_CURVENODE_COMPONENT_X, true);
382 FbxAnimCurve* t_curve_y = skeleton[b]->LclTranslation.GetCurve(
383 anim_layer, FBXSDK_CURVENODE_COMPONENT_Y, true);
384 FbxAnimCurve* t_curve_z = skeleton[b]->LclTranslation.GetCurve(
385 anim_layer, FBXSDK_CURVENODE_COMPONENT_Z, true);
386
387 glm::vec3 v = bone.trans.getValue(cur_anim.Index, t);
388
389 if (bone.parent != -1)
390 {
391 Bone& parent_bone = l_model->bones[bone.parent];
392 v += (bone.pivot - parent_bone.pivot);
393 }
394
395 t_curve_x->KeyModifyBegin();
396 int key_index = t_curve_x->KeyAdd(time);
397 t_curve_x->KeySetValue(key_index, v.x * SCALE_FACTOR);
398 t_curve_x->KeySetInterpolation(key_index, bone.trans.type == INTERPOLATION_LINEAR
399 ? FbxAnimCurveDef::eInterpolationLinear
400 : FbxAnimCurveDef::eInterpolationCubic);
401 t_curve_x->KeyModifyEnd();
402
403 t_curve_y->KeyModifyBegin();
404 key_index = t_curve_y->KeyAdd(time);
405 t_curve_y->KeySetValue(key_index, v.y * SCALE_FACTOR);
406 t_curve_y->KeySetInterpolation(key_index, bone.trans.type == INTERPOLATION_LINEAR
407 ? FbxAnimCurveDef::eInterpolationLinear
408 : FbxAnimCurveDef::eInterpolationCubic);
409 t_curve_y->KeyModifyEnd();
410
411 t_curve_z->KeyModifyBegin();
412 key_index = t_curve_z->KeyAdd(time);
413 t_curve_z->KeySetValue(key_index, v.z * SCALE_FACTOR);
414 t_curve_z->KeySetInterpolation(key_index, bone.trans.type == INTERPOLATION_LINEAR
415 ? FbxAnimCurveDef::eInterpolationLinear
416 : FbxAnimCurveDef::eInterpolationCubic);
417 t_curve_z->KeyModifyEnd();
418 }
419
420 if (rot)
421 {
422 FbxAnimCurve* r_curve_x = skeleton[b]->LclRotation.GetCurve(
423 anim_layer, FBXSDK_CURVENODE_COMPONENT_X, true);
424 FbxAnimCurve* r_curve_y = skeleton[b]->LclRotation.GetCurve(
425 anim_layer, FBXSDK_CURVENODE_COMPONENT_Y, true);
426 FbxAnimCurve* r_curve_z = skeleton[b]->LclRotation.GetCurve(
427 anim_layer, FBXSDK_CURVENODE_COMPONENT_Z, true);
428
429 auto r = glm::eulerAngles(bone.rot.getValue(cur_anim.Index, t));
430
431 auto x = glm::degrees(r.x);
432 auto y = glm::degrees(r.y);
433 auto z = glm::degrees(r.z);
434
435 r_curve_x->KeyModifyBegin();
436 int key_index = r_curve_x->KeyAdd(time);
437 r_curve_x->KeySetValue(key_index, x);
438 r_curve_x->KeySetInterpolation(key_index, bone.rot.type == INTERPOLATION_LINEAR
439 ? FbxAnimCurveDef::eInterpolationLinear
440 : FbxAnimCurveDef::eInterpolationCubic);
441 r_curve_x->KeyModifyEnd();
442
443 r_curve_y->KeyModifyBegin();
444 key_index = r_curve_y->KeyAdd(time);
445 r_curve_y->KeySetValue(key_index, y);
446 r_curve_y->KeySetInterpolation(key_index, bone.rot.type == INTERPOLATION_LINEAR
447 ? FbxAnimCurveDef::eInterpolationLinear
448 : FbxAnimCurveDef::eInterpolationCubic);
449 r_curve_y->KeyModifyEnd();
450
451 r_curve_z->KeyModifyBegin();
452 key_index = r_curve_z->KeyAdd(time);
453 r_curve_z->KeySetValue(key_index, z);
454 r_curve_z->KeySetInterpolation(key_index, bone.rot.type == INTERPOLATION_LINEAR
455 ? FbxAnimCurveDef::eInterpolationLinear
456 : FbxAnimCurveDef::eInterpolationCubic);
457 r_curve_z->KeyModifyEnd();
458 }
459
460 if (scale)
461 {
462 FbxAnimCurve* s_curve_x = skeleton[b]->LclScaling.GetCurve(
463 anim_layer, FBXSDK_CURVENODE_COMPONENT_X, true);
464 FbxAnimCurve* s_curve_y = skeleton[b]->LclScaling.GetCurve(
465 anim_layer, FBXSDK_CURVENODE_COMPONENT_Y, true);
466 FbxAnimCurve* s_curve_z = skeleton[b]->LclScaling.GetCurve(
467 anim_layer, FBXSDK_CURVENODE_COMPONENT_Z, true);
468
469 glm::vec3 v = bone.scale.getValue(cur_anim.Index, t);
470
471 s_curve_x->KeyModifyBegin();
472 int key_index = s_curve_x->KeyAdd(time);
473 s_curve_x->KeySetValue(key_index, v.x);
474 s_curve_x->KeySetInterpolation(key_index, bone.scale.type == INTERPOLATION_LINEAR
475 ? FbxAnimCurveDef::eInterpolationLinear
476 : FbxAnimCurveDef::eInterpolationCubic);
477 s_curve_x->KeyModifyEnd();
478
479 s_curve_y->KeyModifyBegin();
480 key_index = s_curve_y->KeyAdd(time);
481 s_curve_y->KeySetValue(key_index, v.y);
482 s_curve_y->KeySetInterpolation(key_index, bone.scale.type == INTERPOLATION_LINEAR
483 ? FbxAnimCurveDef::eInterpolationLinear
484 : FbxAnimCurveDef::eInterpolationCubic);
485 s_curve_y->KeyModifyEnd();
486
487 s_curve_z->KeyModifyBegin();
488 key_index = s_curve_z->KeyAdd(time);
489 s_curve_z->KeySetValue(key_index, v.z);
490 s_curve_z->KeySetInterpolation(key_index, bone.scale.type == INTERPOLATION_LINEAR
491 ? FbxAnimCurveDef::eInterpolationLinear
492 : FbxAnimCurveDef::eInterpolationCubic);
493 s_curve_z->KeyModifyEnd();
494 }
495 }
496
497 //LOG_INFO << "Ended frame" << t;
498 }
499}
#define SCALE_FACTOR
Definition FBXHeaders.h:37
#define LOG_ERROR
Definition Logger.h:11
#define LOG_INFO
Definition Logger.h:10
@ INTERPOLATION_LINEAR
Linear interpolation.
Definition animated.h:99
T getValue(ssize_t anim, size_t time)
Definition animated.h:178
ssize_t type
Definition animated.h:163
bool uses(ssize_t anim) const
Definition animated.h:171
Represents a single bone in a WoW M2 model skeleton.
Definition Bone.h:20
Animated< glm::fquat, PACK_QUATERNION, Quat16ToQuat32 > rot
Rotation animation track (packed 16-bit).
Definition Bone.h:23
int16 parent
Parent bone index (-1 if root).
Definition Bone.h:27
Animated< glm::vec3 > trans
Translation animation track.
Definition Bone.h:22
Animated< glm::vec3 > scale
Scale animation track.
Definition Bone.h:24
glm::vec3 pivot
Definition Bone.h:26
std::string name() const
Definition Component.cpp:52
Extended geoset with 32-bit index start to support HD models with > 65535 indices.
Represents a single render pass (material + geometry) for an M2 model geoset.
bool init()
Initialise render state from the model's material data.
int geoIndex
Geoset index this pass draws.
Core WoW .m2 model: geometry, animation, textures, and character data.
Definition WoWModel.h:50
std::vector< uint32 > indices
Definition WoWModel.h:139
std::vector< Bone > bones
Definition WoWModel.h:181
std::vector< ModelRenderPass * > passes
Definition WoWModel.h:148
std::vector< ModelGeosetHD * > geosets
Definition WoWModel.h:149
std::vector< ModelVertex > origVertices
Definition WoWModel.h:132
FbxNode * createMesh(FbxManager *&l_manager, FbxScene *&l_scene, WoWModel *model, const glm::mat4 &matrix=glm::mat4(1.0f), const glm::vec3 &offset=glm::vec3(0.0f))
void createSkeleton(WoWModel *l_model, FbxScene *&l_scene, FbxNode *&l_skeletonNode, std::map< int, FbxNode * > &l_boneNodes)
void createAnimation(WoWModel *l_model, FbxScene *&l_scene, std::string animName, ModelAnimation cur_anim, std::map< int, FbxNode * > &skeleton)
void storeBindPose(FbxScene *&l_scene, std::vector< FbxCluster * > l_boneClusters, FbxNode *l_meshNode)
bool createFBXHeaders(FbxString fileVersion, std::string l_FileName, FbxManager *&l_Manager, FbxExporter *&l_Exporter, FbxScene *&l_Scene)
An animation sequence entry in the M2 model (block B).
A vertex as stored in the M2 file (position, bone weights, normal, texcoord).
glm::vec3 normal
glm::vec3 pos
glm::vec2 texcoords
uint32_t uint32
Definition types.h:34