//----------------------------------------------------------------------------// // // // ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation // // and distributed under the MIT License (MIT). // // // // Copyright (c) Guillaume Blanc // // // // Permission is hereby granted, free of charge, to any person obtaining a // // copy of this software and associated documentation files (the "Software"), // // to deal in the Software without restriction, including without limitation // // the rights to use, copy, modify, merge, publish, distribute, sublicense, // // and/or sell copies of the Software, and to permit persons to whom the // // Software is furnished to do so, subject to the following conditions: // // // // The above copyright notice and this permission notice shall be included in // // all copies or substantial portions of the Software. // // // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // // DEALINGS IN THE SOFTWARE. // // // //----------------------------------------------------------------------------// #include "ozz/animation/offline/fbx/fbx.h" #include "ozz/base/log.h" #include "ozz/base/maths/transform.h" #include "ozz/base/memory/allocator.h" namespace ozz { namespace animation { namespace offline { namespace fbx { FbxManagerInstance::FbxManagerInstance() : fbx_manager_(nullptr) { // Instantiate Fbx manager, mostly a memory manager. fbx_manager_ = FbxManager::Create(); // Logs SDK version. ozz::log::Log() << "FBX importer version " << fbx_manager_->GetVersion() << "." << std::endl; } FbxManagerInstance::~FbxManagerInstance() { // Destroy the manager and all associated objects. fbx_manager_->Destroy(); fbx_manager_ = nullptr; } FbxDefaultIOSettings::FbxDefaultIOSettings(const FbxManagerInstance& _manager) : io_settings_(nullptr) { io_settings_ = FbxIOSettings::Create(_manager, IOSROOT); io_settings_->SetBoolProp(IMP_FBX_MATERIAL, false); io_settings_->SetBoolProp(IMP_FBX_TEXTURE, false); io_settings_->SetBoolProp(IMP_FBX_MODEL, false); io_settings_->SetBoolProp(IMP_FBX_SHAPE, false); io_settings_->SetBoolProp(IMP_FBX_LINK, false); io_settings_->SetBoolProp(IMP_FBX_GOBO, false); } FbxDefaultIOSettings::~FbxDefaultIOSettings() { io_settings_->Destroy(); io_settings_ = nullptr; } FbxAnimationIOSettings::FbxAnimationIOSettings( const FbxManagerInstance& _manager) : FbxDefaultIOSettings(_manager) {} FbxSkeletonIOSettings::FbxSkeletonIOSettings(const FbxManagerInstance& _manager) : FbxDefaultIOSettings(_manager) { settings()->SetBoolProp(IMP_FBX_ANIMATION, false); } FbxSceneLoader::FbxSceneLoader(const char* _filename, const char* _password, const FbxManagerInstance& _manager, const FbxDefaultIOSettings& _io_settings) : scene_(nullptr), converter_(nullptr) { // Create an importer. FbxImporter* importer = FbxImporter::Create(_manager, "ozz file importer"); const bool initialized = importer->Initialize(_filename, -1, _io_settings); ImportScene(importer, initialized, _password, _manager, _io_settings); // Destroy the importer importer->Destroy(); } FbxSceneLoader::FbxSceneLoader(FbxStream* _stream, const char* _password, const FbxManagerInstance& _manager, const FbxDefaultIOSettings& _io_settings) : scene_(nullptr), converter_(nullptr) { // Create an importer. FbxImporter* importer = FbxImporter::Create(_manager, "ozz stream importer"); const bool initialized = importer->Initialize(_stream, nullptr, -1, _io_settings); ImportScene(importer, initialized, _password, _manager, _io_settings); // Destroy the importer importer->Destroy(); } void FbxSceneLoader::ImportScene(FbxImporter* _importer, const bool _initialized, const char* _password, const FbxManagerInstance& _manager, const FbxDefaultIOSettings& _io_settings) { // Get the version of the FBX file format. int major, minor, revision; _importer->GetFileVersion(major, minor, revision); if (!_initialized) // Problem with the file to be imported. { const FbxString error = _importer->GetStatus().GetErrorString(); ozz::log::Err() << "FbxImporter initialization failed with error: " << error.Buffer() << std::endl; if (_importer->GetStatus().GetCode() == FbxStatus::eInvalidFileVersion) { ozz::log::Err() << "FBX file version is " << major << "." << minor << "." << revision << "." << std::endl; } } else { if (_importer->IsFBX()) { ozz::log::Log() << "FBX file version is " << major << "." << minor << "." << revision << "." << std::endl; } // Load the scene. scene_ = FbxScene::Create(_manager, "ozz scene"); bool imported = _importer->Import(scene_); if (!imported && // The import file may have a password _importer->GetStatus().GetCode() == FbxStatus::ePasswordError) { _io_settings.settings()->SetStringProp(IMP_FBX_PASSWORD, _password); _io_settings.settings()->SetBoolProp(IMP_FBX_PASSWORD_ENABLE, true); // Retries to import the scene. imported = _importer->Import(scene_); if (!imported && _importer->GetStatus().GetCode() == FbxStatus::ePasswordError) { ozz::log::Err() << "Incorrect password." << std::endl; // scene_ will be destroyed because imported is false. } } // Setup axis and system converter. if (imported) { FbxGlobalSettings& settings = scene_->GetGlobalSettings(); converter_ = New(settings.GetAxisSystem(), settings.GetSystemUnit()); } // Clear the scene if import failed. if (!imported) { scene_->Destroy(); scene_ = nullptr; } } } FbxSceneLoader::~FbxSceneLoader() { if (scene_) { scene_->Destroy(); scene_ = nullptr; } if (converter_) { ozz::Delete(converter_); converter_ = nullptr; } } namespace { ozz::math::Float4x4 BuildAxisSystemMatrix(const FbxAxisSystem& _system) { int sign; ozz::math::SimdFloat4 up = ozz::math::simd_float4::y_axis(); ozz::math::SimdFloat4 at = ozz::math::simd_float4::z_axis(); // The EUpVector specifies which axis has the up and down direction in the // system (typically this is the Y or Z axis). The sign of the EUpVector is // applied to represent the direction (1 is up and -1 is down relative to the // observer). const FbxAxisSystem::EUpVector eup = _system.GetUpVector(sign); switch (eup) { case FbxAxisSystem::eXAxis: { up = math::simd_float4::Load(1.f * sign, 0.f, 0.f, 0.f); // If the up axis is X, the remain two axes will be Y And Z, so the // ParityEven is Y, and the ParityOdd is Z if (_system.GetFrontVector(sign) == FbxAxisSystem::eParityEven) { at = math::simd_float4::Load(0.f, 1.f * sign, 0.f, 0.f); } else { at = math::simd_float4::Load(0.f, 0.f, 1.f * sign, 0.f); } break; } case FbxAxisSystem::eYAxis: { up = math::simd_float4::Load(0.f, 1.f * sign, 0.f, 0.f); // If the up axis is Y, the remain two axes will X And Z, so the // ParityEven is X, and the ParityOdd is Z if (_system.GetFrontVector(sign) == FbxAxisSystem::eParityEven) { at = math::simd_float4::Load(1.f * sign, 0.f, 0.f, 0.f); } else { at = math::simd_float4::Load(0.f, 0.f, 1.f * sign, 0.f); } break; } case FbxAxisSystem::eZAxis: { up = math::simd_float4::Load(0.f, 0.f, 1.f * sign, 0.f); // If the up axis is Z, the remain two axes will X And Y, so the // ParityEven is X, and the ParityOdd is Y if (_system.GetFrontVector(sign) == FbxAxisSystem::eParityEven) { at = math::simd_float4::Load(1.f * sign, 0.f, 0.f, 0.f); } else { at = math::simd_float4::Load(0.f, 1.f * sign, 0.f, 0.f); } break; } default: { assert(false && "Invalid FbxAxisSystem"); break; } } // If the front axis and the up axis are determined, the third axis will be // automatically determined as the left one. The ECoordSystem enum is a // parameter to determine the direction of the third axis just as the // EUpVector sign. It determines if the axis system is right-handed or // left-handed just as the enum values. ozz::math::SimdFloat4 right; if (_system.GetCoorSystem() == FbxAxisSystem::eRightHanded) { right = math::Cross3(up, at); } else { right = math::Cross3(at, up); } const ozz::math::Float4x4 matrix = { {right, up, at, ozz::math::simd_float4::w_axis()}}; return matrix; } } // namespace FbxSystemConverter::FbxSystemConverter(const FbxAxisSystem& _from_axis, const FbxSystemUnit& _from_unit) { // Build axis system conversion matrix. const math::Float4x4 from_matrix = BuildAxisSystemMatrix(_from_axis); // Finds unit conversion ratio to meters, where GetScaleFactor() is in cm. const float to_meters = static_cast(_from_unit.GetScaleFactor()) * .01f; // Builds conversion matrices. convert_ = Invert(from_matrix) * math::Float4x4::Scaling(math::simd_float4::Load1(to_meters)); inverse_convert_ = Invert(convert_); inverse_transpose_convert_ = Transpose(inverse_convert_); } math::Float4x4 FbxSystemConverter::ConvertMatrix(const FbxAMatrix& _m) const { const ozz::math::Float4x4 m = {{ ozz::math::simd_float4::Load( static_cast(_m[0][0]), static_cast(_m[0][1]), static_cast(_m[0][2]), static_cast(_m[0][3])), ozz::math::simd_float4::Load( static_cast(_m[1][0]), static_cast(_m[1][1]), static_cast(_m[1][2]), static_cast(_m[1][3])), ozz::math::simd_float4::Load( static_cast(_m[2][0]), static_cast(_m[2][1]), static_cast(_m[2][2]), static_cast(_m[2][3])), ozz::math::simd_float4::Load( static_cast(_m[3][0]), static_cast(_m[3][1]), static_cast(_m[3][2]), static_cast(_m[3][3])), }}; return convert_ * m * inverse_convert_; } math::Float3 FbxSystemConverter::ConvertPoint(const FbxVector4& _p) const { const math::SimdFloat4 p_in = math::simd_float4::Load( static_cast(_p[0]), static_cast(_p[1]), static_cast(_p[2]), 1.f); const math::SimdFloat4 p_out = convert_ * p_in; math::Float3 ret; math::Store3PtrU(p_out, &ret.x); return ret; } math::Float3 FbxSystemConverter::ConvertVector(const FbxVector4& _p) const { const math::SimdFloat4 p_in = math::simd_float4::Load( static_cast(_p[0]), static_cast(_p[1]), static_cast(_p[2]), 0.f); const math::SimdFloat4 p_out = inverse_transpose_convert_ * p_in; math::Float3 ret; math::Store3PtrU(p_out, &ret.x); return ret; } bool FbxSystemConverter::ConvertTransform(const FbxAMatrix& _m, math::Transform* _transform) const { assert(_transform); const math::Float4x4 matrix = ConvertMatrix(_m); math::SimdFloat4 translation, rotation, scale; if (ToAffine(matrix, &translation, &rotation, &scale)) { ozz::math::Transform transform; math::Store3PtrU(translation, &_transform->translation.x); math::StorePtrU(math::Normalize4(rotation), &_transform->rotation.x); math::Store3PtrU(scale, &_transform->scale.x); return true; } // Failed to decompose matrix, reset transform to identity. *_transform = ozz::math::Transform::identity(); return false; } } // namespace fbx } // namespace offline } // namespace animation } // namespace ozz