void CFbxExporter::Export( const String& assetFolder, const String& resourceFolder, const String& filePath ) { log::Log log(new log::DefaultMessages(), -1); FbxConv conv(&log); Settings settings; settings.flipV = false; settings.packColors = false; settings.verbose = true; settings.maxNodePartBonesCount = 120; settings.maxVertexBonesCount = 4; settings.maxVertexCount = INT_MAX; // (1 << 15) - 1; settings.maxIndexCount = INT_MAX; // (1 << 15) - 1; settings.outType = FILETYPE_AUTO; settings.inType = FILETYPE_FBX; settings.inFile = std::string( (assetFolder + filePath).c_str() ); modeldata::Model *model = new modeldata::Model(); if (!conv.load(&settings, model)) { return; } conv.info(model); CSkeleton* pLastSkeleton = nullptr; for (Node* node : model->nodes) { CSkeleton* pSkeleton = new CSkeleton(); ParseModelNode( node, *pSkeleton, "" ); pSkeleton->ComputeGlobalPose(pSkeleton->m_localBindPose, pSkeleton->m_globalBindPose); String skeletonPath = resourceFolder + filePath.get_path_base() + filePath.get_path_name() + ".skel"; gVars->pFileSystem->CreateFileDir( skeletonPath ); pSkeleton->SaveToFile( skeletonPath ); if ( pLastSkeleton != nullptr ) { delete pLastSkeleton; } pLastSkeleton = pSkeleton; } for (Animation* ani : model->animations) { CAnimation* pAnimation = new CAnimation(); for (NodeAnimation* nodeAnim : ani->nodeAnimations) { int idx = pLastSkeleton->m_boneNameToIndex[nodeAnim->node->id.c_str()]; if (idx < 0) continue; const std::vector< Keyframe* >& keyframes = nodeAnim->keyframes; Transform* trackKeys = new Transform[ keyframes.size() ]; for (size_t iKey = 0; iKey < keyframes.size(); ++iKey) { const Keyframe& k = *(keyframes[ iKey ]); Transform transf; transf.rotation = Quat(k.rotation[3], k.rotation[0], k.rotation[1], k.rotation[2]); if (transf.rotation.w < 0.0f) { transf.rotation = -1.0f * transf.rotation; } transf.position = Vec3(k.translation[0], k.translation[1], k.translation[2]); transf.scale = Vec3(k.scale[0], k.scale[1], k.scale[2]); transf = pLastSkeleton->m_localBindPose.m_boneTransforms[idx].GetInverse() * transf; if (String(nodeAnim->node->id.c_str()).Contains("twist")) { transf = Transform(); } trackKeys[ iKey ] = transf; } pAnimation->AddAnimationTack( new CAnimationTrack( CAnimationTrack::eKFF_Transform, trackKeys, keyframes.size() ), idx ); } String animPath = resourceFolder + filePath.get_path_base() + filePath.get_path_name() + ".anim"; gVars->pFileSystem->CreateFileDir(animPath); pAnimation->SaveToFile(animPath); delete pAnimation; } if (pLastSkeleton != nullptr) { delete pLastSkeleton; } for (Mesh* mesh : model->meshes) { CMeshHelper mh; size_t vertexCount = mesh->vertexCount(); size_t vertexFloatCount = mesh->vertexSize; mh.m_positionArray.reserve(vertexCount); mh.m_normalArray.reserve(vertexCount); size_t attCount = mesh->attributes.length(); for (size_t att = 0; att < attCount; ++att) { size_t idx = mesh->attributes.get(att); unsigned int offset = 0; for (unsigned int i = 0; i < idx; i++) if (mesh->attributes.has(i)) offset += (unsigned int)ATTRIBUTE_SIZE(i); switch (idx) { case ATTRIBUTE_POSITION: { for (size_t i = 0; i < vertexCount; ++i) { mh.AddPosition(*(Vec3*)(&mesh->vertices[vertexFloatCount * i])); } break; } case ATTRIBUTE_NORMAL: { for (size_t i = 0; i < vertexCount; ++i) { mh.AddNormal(*(Vec3*)(&mesh->vertices[offset + vertexFloatCount * i])); } break; } case ATTRIBUTE_BLENDWEIGHT0: case ATTRIBUTE_BLENDWEIGHT1: case ATTRIBUTE_BLENDWEIGHT2: case ATTRIBUTE_BLENDWEIGHT3: case ATTRIBUTE_BLENDWEIGHT4: case ATTRIBUTE_BLENDWEIGHT5: case ATTRIBUTE_BLENDWEIGHT6: case ATTRIBUTE_BLENDWEIGHT7: { size_t attributeIndex = idx - (size_t)ATTRIBUTE_BLENDWEIGHT0; for (size_t i = 0; i < vertexCount; ++i) { mh.AddBlendWeight( attributeIndex, *((SVertexBlendWeight*)(&mesh->vertices[offset + vertexFloatCount * i])) ); } break; } } } for (MeshPart* meshPart : mesh->parts) { mh.AddMeshPart(); CMeshPartHelper* part = mh.GetMeshPart(mh.m_meshParts.size()-1); for (unsigned short indice : meshPart->indices) { part->AddIndex(indice); } } String meshPath = resourceFolder + filePath.get_path_base() + filePath.get_path_name() + ".msh"; gVars->pFileSystem->CreateFileDir( meshPath ); mh.SaveToFile( meshPath ); } }