Merge branch 'master' into master

pull/4542/head
hgdagon 2022-06-13 00:15:31 +04:00 committed by GitHub
commit ce8081bd0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 420 additions and 309 deletions

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -87,11 +86,6 @@ AnimationCurve::AnimationCurve(uint64_t id, const Element &element, const std::s
} }
} }
// ------------------------------------------------------------------------------------------------
AnimationCurve::~AnimationCurve() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element &element, const std::string &name, AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element &element, const std::string &name,
const Document &doc, const char *const *target_prop_whitelist /*= nullptr*/, const Document &doc, const char *const *target_prop_whitelist /*= nullptr*/,
@ -147,11 +141,6 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element &element, cons
props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false); props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false);
} }
// ------------------------------------------------------------------------------------------------
AnimationCurveNode::~AnimationCurveNode() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const AnimationCurveMap &AnimationCurveNode::Curves() const { const AnimationCurveMap &AnimationCurveNode::Curves() const {
if (curves.empty()) { if (curves.empty()) {
@ -193,11 +182,6 @@ AnimationLayer::AnimationLayer(uint64_t id, const Element &element, const std::s
props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true); props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true);
} }
// ------------------------------------------------------------------------------------------------
AnimationLayer::~AnimationLayer() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_prop_whitelist /*= nullptr*/, AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_prop_whitelist /*= nullptr*/,
size_t whitelist_size /*= 0*/) const { size_t whitelist_size /*= 0*/) const {
@ -279,11 +263,6 @@ AnimationStack::AnimationStack(uint64_t id, const Element &element, const std::s
} }
} }
// ------------------------------------------------------------------------------------------------
AnimationStack::~AnimationStack() {
// empty
}
} // namespace FBX } // namespace FBX
} // namespace Assimp } // namespace Assimp

View File

@ -50,7 +50,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
namespace FBX { namespace FBX {
const std::string NULL_RECORD = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit static constexpr size_t NumNullRecords = 25;
const char NULL_RECORD[NumNullRecords] = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
}; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?) }; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?)

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,

View File

@ -65,12 +65,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h> #include <stdlib.h>
#include <cstdint> #include <cstdint>
#include <iomanip> #include <iomanip>
#include <iostream>
#include <iterator> #include <iterator>
#include <memory> #include <memory>
#include <sstream> #include <sstream>
#include <tuple>
#include <vector>
namespace Assimp { namespace Assimp {
namespace FBX { namespace FBX {
@ -187,8 +184,7 @@ std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiN
/// This struct manages nodes which may or may not end up in the node hierarchy. /// This struct manages nodes which may or may not end up in the node hierarchy.
/// When a node becomes a child of another node, that node becomes its owner and mOwnership should be released. /// When a node becomes a child of another node, that node becomes its owner and mOwnership should be released.
struct FBXConverter::PotentialNode struct FBXConverter::PotentialNode {
{
PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {} PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {}
PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {} PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {}
aiNode* operator->() { return mNode; } aiNode* operator->() { return mNode; }
@ -231,7 +227,7 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
if (nullptr != model) { if (nullptr != model) {
nodes_chain.clear(); nodes_chain.clear();
post_nodes_chain.clear(); post_nodes_chain.clear();
aiMatrix4x4 new_abs_transform = parent->mTransformation;
std::string node_name = FixNodeName(model->Name()); std::string node_name = FixNodeName(model->Name());
// even though there is only a single input node, the design of // even though there is only a single input node, the design of
// assimp (or rather: the complicated transformation chain that // assimp (or rather: the complicated transformation chain that
@ -268,7 +264,7 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
} }
// attach geometry // attach geometry
ConvertModel(*model, nodes_chain.back().mNode, root_node); ConvertModel(*model, nodes_chain.back().mNode, root_node, new_abs_transform);
// check if there will be any child nodes // check if there will be any child nodes
const std::vector<const Connection *> &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model"); const std::vector<const Connection *> &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model");
@ -447,7 +443,7 @@ void FBXConverter::GetUniqueName(const std::string &name, std::string &uniqueNam
auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count
unsigned int &i = it_pair.first->second; unsigned int &i = it_pair.first->second;
while (!it_pair.second) { while (!it_pair.second) {
i++; ++i;
std::ostringstream ext; std::ostringstream ext;
ext << name << std::setfill('0') << std::setw(3) << i; ext << name << std::setfill('0') << std::setw(3) << i;
uniqueName = ext.str(); uniqueName = ext.str();
@ -646,9 +642,8 @@ void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D &rot
bool FBXConverter::NeedsComplexTransformationChain(const Model &model) { bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
const PropertyTable &props = model.Props(); const PropertyTable &props = model.Props();
bool ok;
const float zero_epsilon = ai_epsilon; const auto zero_epsilon = ai_epsilon;
const aiVector3D all_ones(1.0f, 1.0f, 1.0f); const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) { for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
const TransformationComp comp = static_cast<TransformationComp>(i); const TransformationComp comp = static_cast<TransformationComp>(i);
@ -660,6 +655,7 @@ bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
bool scale_compare = (comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling); bool scale_compare = (comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling);
bool ok = true;
const aiVector3D &v = PropertyGet<aiVector3D>(props, NameTransformationCompProperty(comp), ok); const aiVector3D &v = PropertyGet<aiVector3D>(props, NameTransformationCompProperty(comp), ok);
if (ok && scale_compare) { if (ok && scale_compare) {
if ((v - all_ones).SquareLength() > zero_epsilon) { if ((v - all_ones).SquareLength() > zero_epsilon) {
@ -894,18 +890,17 @@ void FBXConverter::SetupNodeMetadata(const Model &model, aiNode &nd) {
} }
} }
void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root_node) { void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform) {
const std::vector<const Geometry *> &geos = model.GetGeometry(); const std::vector<const Geometry *> &geos = model.GetGeometry();
std::vector<unsigned int> meshes; std::vector<unsigned int> meshes;
meshes.reserve(geos.size()); meshes.reserve(geos.size());
for (const Geometry *geo : geos) { for (const Geometry *geo : geos) {
const MeshGeometry *const mesh = dynamic_cast<const MeshGeometry *>(geo); const MeshGeometry *const mesh = dynamic_cast<const MeshGeometry *>(geo);
const LineGeometry *const line = dynamic_cast<const LineGeometry *>(geo); const LineGeometry *const line = dynamic_cast<const LineGeometry *>(geo);
if (mesh) { if (mesh) {
const std::vector<unsigned int> &indices = ConvertMesh(*mesh, model, parent, root_node); const std::vector<unsigned int> &indices = ConvertMesh(*mesh, model, parent, root_node, absolute_transform);
std::copy(indices.begin(), indices.end(), std::back_inserter(meshes)); std::copy(indices.begin(), indices.end(), std::back_inserter(meshes));
} else if (line) { } else if (line) {
const std::vector<unsigned int> &indices = ConvertLine(*line, root_node); const std::vector<unsigned int> &indices = ConvertLine(*line, root_node);
@ -926,7 +921,7 @@ void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root
} }
std::vector<unsigned int> std::vector<unsigned int>
FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node) { FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform) {
std::vector<unsigned int> temp; std::vector<unsigned int> temp;
MeshMap::const_iterator it = meshes_converted.find(&mesh); MeshMap::const_iterator it = meshes_converted.find(&mesh);
@ -949,13 +944,13 @@ FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *
const MatIndexArray::value_type base = mindices[0]; const MatIndexArray::value_type base = mindices[0];
for (MatIndexArray::value_type index : mindices) { for (MatIndexArray::value_type index : mindices) {
if (index != base) { if (index != base) {
return ConvertMeshMultiMaterial(mesh, model, parent, root_node); return ConvertMeshMultiMaterial(mesh, model, absolute_transform, parent, root_node);
} }
} }
} }
// faster code-path, just copy the data // faster code-path, just copy the data
temp.push_back(ConvertMeshSingleMaterial(mesh, model, parent, root_node)); temp.push_back(ConvertMeshSingleMaterial(mesh, model, absolute_transform, parent, root_node));
return temp; return temp;
} }
@ -1023,7 +1018,35 @@ aiMesh *FBXConverter::SetupEmptyMesh(const Geometry &mesh, aiNode *parent) {
return out_mesh; return out_mesh;
} }
unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, static aiSkeleton *createAiSkeleton(SkeletonBoneContainer &sbc) {
if (sbc.MeshArray.empty() || sbc.SkeletonBoneToMeshLookup.empty()) {
return nullptr;
}
aiSkeleton *skeleton = new aiSkeleton;
for (auto *mesh : sbc.MeshArray) {
auto it = sbc.SkeletonBoneToMeshLookup.find(mesh);
if (it == sbc.SkeletonBoneToMeshLookup.end()) {
continue;
}
SkeletonBoneArray *ba = it->second;
if (ba == nullptr) {
continue;
}
skeleton->mNumBones = static_cast<unsigned int>(ba->size());
skeleton->mBones = new aiSkeletonBone*[skeleton->mNumBones];
size_t index = 0;
for (auto bone : (* ba)) {
skeleton->mBones[index] = bone;
++index;
}
}
return skeleton;
}
unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform,
aiNode *parent, aiNode *) { aiNode *parent, aiNode *) {
const MatIndexArray &mindices = mesh.GetMaterialIndices(); const MatIndexArray &mindices = mesh.GetMaterialIndices();
aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent); aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent);
@ -1142,8 +1165,15 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]); ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]);
} }
if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr) { if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr && !doc.Settings().useSkeleton) {
ConvertWeights(out_mesh, mesh, parent, NO_MATERIAL_SEPARATION, nullptr); ConvertWeights(out_mesh, mesh, absolute_transform, parent, NO_MATERIAL_SEPARATION, nullptr);
} else if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr && doc.Settings().useSkeleton) {
SkeletonBoneContainer sbc;
ConvertWeightsToSkeleton(out_mesh, mesh, absolute_transform, parent, NO_MATERIAL_SEPARATION, nullptr, sbc);
aiSkeleton *skeleton = createAiSkeleton(sbc);
if (skeleton != nullptr) {
mSkeletons.emplace_back(skeleton);
}
} }
std::vector<aiAnimMesh *> animMeshes; std::vector<aiAnimMesh *> animMeshes;
@ -1190,7 +1220,7 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
} }
std::vector<unsigned int> std::vector<unsigned int>
FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent, FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform, aiNode *parent,
aiNode *root_node) { aiNode *root_node) {
const MatIndexArray &mindices = mesh.GetMaterialIndices(); const MatIndexArray &mindices = mesh.GetMaterialIndices();
ai_assert(mindices.size()); ai_assert(mindices.size());
@ -1201,7 +1231,7 @@ FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &mo
for (MatIndexArray::value_type index : mindices) { for (MatIndexArray::value_type index : mindices) {
if (had.find(index) == had.end()) { if (had.find(index) == had.end()) {
indices.push_back(ConvertMeshMultiMaterial(mesh, model, index, parent, root_node)); indices.push_back(ConvertMeshMultiMaterial(mesh, model, absolute_transform, index, parent, root_node));
had.insert(index); had.insert(index);
} }
} }
@ -1209,9 +1239,8 @@ FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &mo
return indices; return indices;
} }
unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform,
MatIndexArray::value_type index, MatIndexArray::value_type index, aiNode *parent, aiNode *) {
aiNode *parent, aiNode *) {
aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent); aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent);
const MatIndexArray &mindices = mesh.GetMaterialIndices(); const MatIndexArray &mindices = mesh.GetMaterialIndices();
@ -1374,7 +1403,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
ConvertMaterialForMesh(out_mesh, model, mesh, index); ConvertMaterialForMesh(out_mesh, model, mesh, index);
if (process_weights) { if (process_weights) {
ConvertWeights(out_mesh, mesh, parent, index, &reverseMapping); ConvertWeights(out_mesh, mesh, absolute_transform, parent, index, &reverseMapping);
} }
std::vector<aiAnimMesh *> animMeshes; std::vector<aiAnimMesh *> animMeshes;
@ -1424,19 +1453,47 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
return static_cast<unsigned int>(mMeshes.size() - 1); return static_cast<unsigned int>(mMeshes.size() - 1);
} }
void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo, static void copyBoneToSkeletonBone(aiMesh *mesh, aiBone *bone, aiSkeletonBone *skeletonBone ) {
skeletonBone->mNumnWeights = bone->mNumWeights;
skeletonBone->mWeights = bone->mWeights;
skeletonBone->mOffsetMatrix = bone->mOffsetMatrix;
skeletonBone->mMeshId = mesh;
skeletonBone->mNode = bone->mNode;
skeletonBone->mParent = -1;
}
void FBXConverter::ConvertWeightsToSkeleton(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform, aiNode *parent, unsigned int materialIndex,
std::vector<unsigned int> *outputVertStartIndices, SkeletonBoneContainer &skeletonContainer) {
if (skeletonContainer.SkeletonBoneToMeshLookup.find(out) != skeletonContainer.SkeletonBoneToMeshLookup.end()) {
return;
}
ConvertWeights(out, geo, absolute_transform, parent, materialIndex, outputVertStartIndices);
skeletonContainer.MeshArray.emplace_back(out);
SkeletonBoneArray *ba = new SkeletonBoneArray;
for (size_t i = 0; i < out->mNumBones; ++i) {
aiBone *bone = out->mBones[i];
if (bone == nullptr) {
continue;
}
aiSkeletonBone *skeletonBone = new aiSkeletonBone;
copyBoneToSkeletonBone(out, bone, skeletonBone);
ba->emplace_back(skeletonBone);
}
skeletonContainer.SkeletonBoneToMeshLookup[out] = ba;
}
void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
aiNode *parent, unsigned int materialIndex, aiNode *parent, unsigned int materialIndex,
std::vector<unsigned int> *outputVertStartIndices) { std::vector<unsigned int> *outputVertStartIndices) {
ai_assert(geo.DeformerSkin()); ai_assert(geo.DeformerSkin());
std::vector<size_t> out_indices; std::vector<size_t> out_indices, index_out_indices, count_out_indices;
std::vector<size_t> index_out_indices;
std::vector<size_t> count_out_indices;
const Skin &sk = *geo.DeformerSkin(); const Skin &sk = *geo.DeformerSkin();
std::vector<aiBone *> bones; std::vector<aiBone*> bones;
const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION; const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION;
ai_assert(no_mat_check || outputVertStartIndices); ai_assert(no_mat_check || outputVertStartIndices);
@ -1496,7 +1553,7 @@ void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo,
// XXX this could be heavily simplified by collecting the bone // XXX this could be heavily simplified by collecting the bone
// data in a single step. // data in a single step.
ConvertCluster(bones, cluster, out_indices, index_out_indices, ConvertCluster(bones, cluster, out_indices, index_out_indices,
count_out_indices, parent); count_out_indices, absolute_transform, parent);
} }
bone_map.clear(); bone_map.clear();
@ -1509,25 +1566,20 @@ void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo,
out->mBones = nullptr; out->mBones = nullptr;
out->mNumBones = 0; out->mNumBones = 0;
return; return;
} else { }
out->mBones = new aiBone *[bones.size()]();
out->mNumBones = static_cast<unsigned int>(bones.size());
std::swap_ranges(bones.begin(), bones.end(), out->mBones); out->mBones = new aiBone *[bones.size()]();
} out->mNumBones = static_cast<unsigned int>(bones.size());
std::swap_ranges(bones.begin(), bones.end(), out->mBones);
} }
const aiNode *GetNodeByName(aiNode *current_node) { void FBXConverter::ConvertCluster(std::vector<aiBone*> &local_mesh_bones, const Cluster *cluster,
aiNode *iter = current_node;
//printf("Child count: %d", iter->mNumChildren);
return iter;
}
void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices, std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
std::vector<size_t> &count_out_indices, aiNode *) { std::vector<size_t> &count_out_indices, const aiMatrix4x4 & /* absolute_transform*/,
ai_assert(cl); // make sure cluster valid aiNode *) {
std::string deformer_name = cl->TargetNode()->Name(); ai_assert(cluster != nullptr); // make sure cluster valid
std::string deformer_name = cluster->TargetNode()->Name();
aiString bone_name = aiString(FixNodeName(deformer_name)); aiString bone_name = aiString(FixNodeName(deformer_name));
aiBone *bone = nullptr; aiBone *bone = nullptr;
@ -1540,10 +1592,10 @@ void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const
bone = new aiBone(); bone = new aiBone();
bone->mName = bone_name; bone->mName = bone_name;
bone->mOffsetMatrix = cl->Transform(); bone->mOffsetMatrix = cluster->Transform();
// store local transform link for post processing // store local transform link for post processing
/* /*
bone->mOffsetMatrix = cl->TransformLink(); bone->mOffsetMatrix = cluster->TransformLink();
bone->mOffsetMatrix.Inverse(); bone->mOffsetMatrix.Inverse();
aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform; aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform;
@ -1560,7 +1612,7 @@ void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const
cursor = bone->mWeights = new aiVertexWeight[out_indices.size()]; cursor = bone->mWeights = new aiVertexWeight[out_indices.size()];
const size_t no_index_sentinel = std::numeric_limits<size_t>::max(); const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
const WeightArray &weights = cl->GetWeights(); const WeightArray &weights = cluster->GetWeights();
const size_t c = index_out_indices.size(); const size_t c = index_out_indices.size();
for (size_t i = 0; i < c; ++i) { for (size_t i = 0; i < c; ++i) {
@ -2605,7 +2657,7 @@ void FBXConverter::ConvertAnimationStack(const AnimationStack &st) {
meshMorphAnim->mNumKeys = numKeys; meshMorphAnim->mNumKeys = numKeys;
meshMorphAnim->mKeys = new aiMeshMorphKey[numKeys]; meshMorphAnim->mKeys = new aiMeshMorphKey[numKeys];
unsigned int j = 0; unsigned int j = 0;
for (auto animIt : *animData) { for (auto &animIt : *animData) {
morphKeyData *keyData = animIt.second; morphKeyData *keyData = animIt.second;
unsigned int numValuesAndWeights = static_cast<unsigned int>(keyData->values.size()); unsigned int numValuesAndWeights = static_cast<unsigned int>(keyData->values.size());
meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights; meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights;
@ -3180,7 +3232,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
bool ok = false; bool ok = false;
const float zero_epsilon = ai_epsilon; const auto zero_epsilon = ai_epsilon;
const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok); const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);
if (ok && preRotation.SquareLength() > zero_epsilon) { if (ok && preRotation.SquareLength() > zero_epsilon) {
@ -3625,6 +3677,12 @@ void FBXConverter::TransferDataToScene() {
std::swap_ranges(textures.begin(), textures.end(), mSceneOut->mTextures); std::swap_ranges(textures.begin(), textures.end(), mSceneOut->mTextures);
} }
if (!mSkeletons.empty()) {
mSceneOut->mSkeletons = new aiSkeleton *[mSkeletons.size()];
mSceneOut->mNumSkeletons = static_cast<unsigned int>(mSkeletons.size());
std::swap_ranges(mSkeletons.begin(), mSkeletons.end(), mSceneOut->mSkeletons);
}
} }
void FBXConverter::ConvertOrphanedEmbeddedTextures() { void FBXConverter::ConvertOrphanedEmbeddedTextures() {

View File

@ -75,7 +75,18 @@ typedef std::map<int64_t, morphKeyData*> morphAnimData;
namespace Assimp { namespace Assimp {
namespace FBX { namespace FBX {
class MeshGeometry;
using SkeletonBoneArray = std::vector<aiSkeletonBone *>;
using SkeletonBoneToMesh = std::map<aiMesh*, SkeletonBoneArray*>;
struct SkeletonBoneContainer {
std::vector<aiMesh *> MeshArray;
SkeletonBoneToMesh SkeletonBoneToMeshLookup;
};
class Document; class Document;
/** /**
* Convert a FBX #Document to #aiScene * Convert a FBX #Document to #aiScene
* @param out Empty scene to be populated * @param out Empty scene to be populated
@ -180,12 +191,12 @@ private:
void SetupNodeMetadata(const Model& model, aiNode& nd); void SetupNodeMetadata(const Model& model, aiNode& nd);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertModel(const Model &model, aiNode *parent, aiNode *root_node); void ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed // MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed
std::vector<unsigned int> std::vector<unsigned int>
ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node); ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::vector<unsigned int> ConvertLine(const LineGeometry& line, aiNode *root_node); std::vector<unsigned int> ConvertLine(const LineGeometry& line, aiNode *root_node);
@ -194,15 +205,15 @@ private:
aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode *parent); aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode *parent);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
unsigned int ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, unsigned int ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform,
aiNode *parent, aiNode *root_node); aiNode *parent, aiNode *root_node);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::vector<unsigned int> std::vector<unsigned int>
ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node); ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform, aiNode *parent, aiNode *root_node);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
unsigned int ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, MatIndexArray::value_type index, unsigned int ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform, MatIndexArray::value_type index,
aiNode *parent, aiNode *root_node); aiNode *parent, aiNode *root_node);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -216,14 +227,19 @@ private:
* - outputVertStartIndices is only used when a material index is specified, it gives for * - outputVertStartIndices is only used when a material index is specified, it gives for
* each output vertex the DOM index it maps to. * each output vertex the DOM index it maps to.
*/ */
void ConvertWeights(aiMesh *out, const MeshGeometry &geo, aiNode *parent = nullptr, void ConvertWeights(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform, aiNode *parent = nullptr,
unsigned int materialIndex = NO_MATERIAL_SEPARATION, unsigned int materialIndex = NO_MATERIAL_SEPARATION,
std::vector<unsigned int> *outputVertStartIndices = nullptr); std::vector<unsigned int> *outputVertStartIndices = nullptr);
// ------------------------------------------------------------------------------------------------
void ConvertWeightsToSkeleton(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
aiNode *parent, unsigned int materialIndex, std::vector<unsigned int> *outputVertStartIndices,
SkeletonBoneContainer &skeletonContainer);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl, void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices, std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
std::vector<size_t> &count_out_indices, aiNode *parent ); std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform, aiNode *parent);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo, void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo,
@ -296,7 +312,8 @@ private:
void ConvertAnimationStack(const AnimationStack& st); void ConvertAnimationStack(const AnimationStack& st);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessMorphAnimDatas(std::map<std::string, morphAnimData*>* morphAnimDatas, const BlendShapeChannel* bsc, const AnimationCurveNode* node); void ProcessMorphAnimDatas(std::map<std::string, morphAnimData*>* morphAnimDatas,
const BlendShapeChannel* bsc, const AnimationCurveNode* node);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void GenerateNodeAnimations(std::vector<aiNodeAnim*>& node_anims, void GenerateNodeAnimations(std::vector<aiNodeAnim*>& node_anims,
@ -445,6 +462,7 @@ private:
double anim_fps; double anim_fps;
std::vector<aiSkeleton *> mSkeletons;
aiScene* const mSceneOut; aiScene* const mSceneOut;
const FBX::Document& doc; const FBX::Document& doc;
bool mRemoveEmptyBones; bool mRemoveEmptyBones;

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -58,16 +57,14 @@ namespace FBX {
using namespace Util; using namespace Util;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Deformer::Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name) Deformer::Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name) :
: Object(id,element,name) Object(id,element,name) {
{
const Scope& sc = GetRequiredScope(element); const Scope& sc = GetRequiredScope(element);
const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2)); const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true); props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Deformer::~Deformer() Deformer::~Deformer()
{ {

View File

@ -67,7 +67,7 @@ namespace FBX {
using namespace Util; using namespace Util;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
LazyObject::LazyObject(uint64_t id, const Element& element, const Document& doc) : LazyObject::LazyObject(uint64_t id, const Element& element, const Document& doc) :
doc(doc), element(element), id(id), flags() { doc(doc), element(element), id(id), flags() {
// empty // empty
} }
@ -544,7 +544,7 @@ std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bo
ai_assert( count != 0 ); ai_assert( count != 0 );
ai_assert( count <= MAX_CLASSNAMES); ai_assert( count <= MAX_CLASSNAMES);
size_t lengths[MAX_CLASSNAMES]; size_t lengths[MAX_CLASSNAMES] = {};
const size_t c = count; const size_t c = count;
for (size_t i = 0; i < c; ++i) { for (size_t i = 0; i < c; ++i) {

View File

@ -164,7 +164,7 @@ class NodeAttribute : public Object {
public: public:
NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name); NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name);
virtual ~NodeAttribute(); virtual ~NodeAttribute() = default;
const PropertyTable& Props() const { const PropertyTable& Props() const {
ai_assert(props.get()); ai_assert(props.get());
@ -180,7 +180,7 @@ class CameraSwitcher : public NodeAttribute {
public: public:
CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name); CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name);
virtual ~CameraSwitcher(); virtual ~CameraSwitcher() = default;
int CameraID() const { int CameraID() const {
return cameraId; return cameraId;
@ -225,7 +225,7 @@ class Camera : public NodeAttribute {
public: public:
Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name); Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name);
virtual ~Camera(); virtual ~Camera() = default;
fbx_simple_property(Position, aiVector3D, aiVector3D(0,0,0)) fbx_simple_property(Position, aiVector3D, aiVector3D(0,0,0))
fbx_simple_property(UpVector, aiVector3D, aiVector3D(0,1,0)) fbx_simple_property(UpVector, aiVector3D, aiVector3D(0,1,0))
@ -250,21 +250,21 @@ public:
class Null : public NodeAttribute { class Null : public NodeAttribute {
public: public:
Null(uint64_t id, const Element& element, const Document& doc, const std::string& name); Null(uint64_t id, const Element& element, const Document& doc, const std::string& name);
virtual ~Null(); virtual ~Null() = default;
}; };
/** DOM base class for FBX limb node markers attached to a node */ /** DOM base class for FBX limb node markers attached to a node */
class LimbNode : public NodeAttribute { class LimbNode : public NodeAttribute {
public: public:
LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name); LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name);
virtual ~LimbNode(); virtual ~LimbNode() = default;
}; };
/** DOM base class for FBX lights attached to a node */ /** DOM base class for FBX lights attached to a node */
class Light : public NodeAttribute { class Light : public NodeAttribute {
public: public:
Light(uint64_t id, const Element& element, const Document& doc, const std::string& name); Light(uint64_t id, const Element& element, const Document& doc, const std::string& name);
virtual ~Light(); virtual ~Light() = default;
enum Type { enum Type {
Type_Point, Type_Point,
@ -690,7 +690,7 @@ using KeyValueList = std::vector<float>;
class AnimationCurve : public Object { class AnimationCurve : public Object {
public: public:
AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& doc); AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& doc);
virtual ~AnimationCurve(); virtual ~AnimationCurve() = default;
/** get list of keyframe positions (time). /** get list of keyframe positions (time).
* Invariant: |GetKeys()| > 0 */ * Invariant: |GetKeys()| > 0 */
@ -731,7 +731,7 @@ public:
AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, const Document& doc, AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, const Document& doc,
const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0); const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0);
virtual ~AnimationCurveNode(); virtual ~AnimationCurveNode() = default;
const PropertyTable& Props() const { const PropertyTable& Props() const {
ai_assert(props.get()); ai_assert(props.get());
@ -776,7 +776,7 @@ using AnimationCurveNodeList = std::vector<const AnimationCurveNode*>;
class AnimationLayer : public Object { class AnimationLayer : public Object {
public: public:
AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc); AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc);
virtual ~AnimationLayer(); virtual ~AnimationLayer() = default;
const PropertyTable& Props() const { const PropertyTable& Props() const {
ai_assert(props.get()); ai_assert(props.get());
@ -799,7 +799,7 @@ using AnimationLayerList = std::vector<const AnimationLayer*>;
class AnimationStack : public Object { class AnimationStack : public Object {
public: public:
AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc); AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc);
virtual ~AnimationStack(); virtual ~AnimationStack() = default;
fbx_simple_property(LocalStart, int64_t, 0L) fbx_simple_property(LocalStart, int64_t, 0L)
fbx_simple_property(LocalStop, int64_t, 0L) fbx_simple_property(LocalStop, int64_t, 0L)

View File

@ -59,14 +59,12 @@ namespace Util {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError. // signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.
void DOMError(const std::string& message, const Token& token) void DOMError(const std::string& message, const Token& token) {
{
throw DeadlyImportError("FBX-DOM", Util::GetTokenText(&token), message); throw DeadlyImportError("FBX-DOM", Util::GetTokenText(&token), message);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void DOMError(const std::string& message, const Element* element /*= nullptr*/) void DOMError(const std::string& message, const Element* element /*= nullptr*/) {
{
if(element) { if(element) {
DOMError(message,element->KeyToken()); DOMError(message,element->KeyToken());
} }
@ -76,8 +74,7 @@ void DOMError(const std::string& message, const Element* element /*= nullptr*/)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// print warning, do return // print warning, do return
void DOMWarning(const std::string& message, const Token& token) void DOMWarning(const std::string& message, const Token& token) {
{
if(DefaultLogger::get()) { if(DefaultLogger::get()) {
ASSIMP_LOG_WARN("FBX-DOM", Util::GetTokenText(&token), message); ASSIMP_LOG_WARN("FBX-DOM", Util::GetTokenText(&token), message);
} }

View File

@ -74,13 +74,11 @@ std::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
template <typename T> template <typename T>
inline inline const T* ProcessSimpleConnection(const Connection& con,
const T* ProcessSimpleConnection(const Connection& con, bool is_object_property_conn,
bool is_object_property_conn, const char* name,
const char* name, const Element& element,
const Element& element, const char** propNameOut = nullptr) {
const char** propNameOut = nullptr)
{
if (is_object_property_conn && !con.PropertyName().length()) { if (is_object_property_conn && !con.PropertyName().length()) {
DOMWarning("expected incoming " + std::string(name) + DOMWarning("expected incoming " + std::string(name) +
" link to be an object-object connection, ignoring", " link to be an object-object connection, ignoring",

View File

@ -255,7 +255,7 @@ void FBXExporter::WriteBinaryHeader()
void FBXExporter::WriteBinaryFooter() void FBXExporter::WriteBinaryFooter()
{ {
outfile->Write(NULL_RECORD.c_str(), NULL_RECORD.size(), 1); outfile->Write(NULL_RECORD, NumNullRecords, 1);
outfile->Write(GENERIC_FOOTID.c_str(), GENERIC_FOOTID.size(), 1); outfile->Write(GENERIC_FOOTID.c_str(), GENERIC_FOOTID.size(), 1);

View File

@ -60,6 +60,7 @@ struct ImportSettings {
readLights(true), readLights(true),
readAnimations(true), readAnimations(true),
readWeights(true), readWeights(true),
useSkeleton(false),
preservePivots(true), preservePivots(true),
optimizeEmptyAnimationCurves(true), optimizeEmptyAnimationCurves(true),
useLegacyEmbeddedTextureNaming(false), useLegacyEmbeddedTextureNaming(false),
@ -112,6 +113,11 @@ struct ImportSettings {
* Default value is true. */ * Default value is true. */
bool readWeights; bool readWeights;
/** will convert all animation data into a skeleton (experimental)
* Default value is false.
*/
bool useSkeleton;
/** preserve transformation pivots and offsets. Since these can /** preserve transformation pivots and offsets. Since these can
* not directly be represented in assimp, additional dummy * not directly be represented in assimp, additional dummy
* nodes will be generated. Note that settings this to false * nodes will be generated. Note that settings this to false

View File

@ -90,12 +90,9 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by #Importer // Constructor to be privately used by #Importer
FBXImporter::FBXImporter() { FBXImporter::FBXImporter() :
} mSettings() {
// empty
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
FBXImporter::~FBXImporter() {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -115,20 +112,21 @@ const aiImporterDesc *FBXImporter::GetInfo() const {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Setup configuration properties for the loader // Setup configuration properties for the loader
void FBXImporter::SetupProperties(const Importer *pImp) { void FBXImporter::SetupProperties(const Importer *pImp) {
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true); mSettings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false); mSettings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true); mSettings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true); mSettings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true); mSettings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true); mSettings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true); mSettings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
settings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true); mSettings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false); mSettings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true); mSettings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true); mSettings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false); mSettings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true); mSettings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false); mSettings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
mSettings.useSkeleton = pImp->GetPropertyBool(AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER, false);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -155,7 +153,7 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
contents[contents.size() - 1] = 0; contents[contents.size() - 1] = 0;
const char *const begin = &*contents.begin(); const char *const begin = &*contents.begin();
// broadphase tokenizing pass in which we identify the core // broad-phase tokenized pass in which we identify the core
// syntax elements of FBX (brackets, commas, key:value mappings) // syntax elements of FBX (brackets, commas, key:value mappings)
TokenList tokens; TokenList tokens;
try { try {
@ -173,15 +171,14 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
Parser parser(tokens, is_binary); Parser parser(tokens, is_binary);
// take the raw parse-tree and convert it to a FBX DOM // take the raw parse-tree and convert it to a FBX DOM
Document doc(parser, settings); Document doc(parser, mSettings);
// convert the FBX DOM to aiScene // convert the FBX DOM to aiScene
ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones); ConvertToAssimpScene(pScene, doc, mSettings.removeEmptyBones);
// size relative to cm // size relative to cm
float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor(); float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
if (size_relative_to_cm == 0.0) if (size_relative_to_cm == 0.0) {
{
// BaseImporter later asserts that fileScale is non-zero. // BaseImporter later asserts that fileScale is non-zero.
ThrowException("The UnitScaleFactor must be non-zero"); ThrowException("The UnitScaleFactor must be non-zero");
} }

View File

@ -69,13 +69,14 @@ typedef class basic_formatter<char, std::char_traits<char>, std::allocator<char>
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> { class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> {
public: public:
/// @brief The class constructor.
FBXImporter(); FBXImporter();
~FBXImporter() override;
// -------------------- /// @brief The class destructor, default implementation.
bool CanRead(const std::string &pFile, ~FBXImporter() override = default;
IOSystem *pIOHandler,
bool checkSig) const override; /// @brief Will check the file for readability.
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
protected: protected:
// -------------------- // --------------------
@ -90,7 +91,7 @@ protected:
IOSystem *pIOHandler) override; IOSystem *pIOHandler) override;
private: private:
FBX::ImportSettings settings; FBX::ImportSettings mSettings;
}; // !class FBXImporter }; // !class FBXImporter
} // end of namespace Assimp } // end of namespace Assimp

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -54,18 +53,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "FBXImportSettings.h" #include "FBXImportSettings.h"
#include "FBXDocumentUtil.h" #include "FBXDocumentUtil.h"
namespace Assimp { namespace Assimp {
namespace FBX { namespace FBX {
using namespace Util; using namespace Util;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) :
: Object(id, element, name) Object(id, element, name), skin() {
, skin() const std::vector<const Connection*> &conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
{
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
for(const Connection* con : conns) { for(const Connection* con : conns) {
const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element); const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
if(sk) { if(sk) {
@ -78,12 +74,6 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name,
} }
} }
// ------------------------------------------------------------------------------------------------
Geometry::~Geometry()
{
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const { const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const {
return blendShapes; return blendShapes;
@ -183,18 +173,12 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
if(doc.Settings().readAllLayers || index == 0) { if(doc.Settings().readAllLayers || index == 0) {
const Scope& layer = GetRequiredScope(*(*it).second); const Scope& layer = GetRequiredScope(*(*it).second);
ReadLayer(layer); ReadLayer(layer);
} } else {
else {
FBXImporter::LogWarn("ignoring additional geometry layers"); FBXImporter::LogWarn("ignoring additional geometry layers");
} }
} }
} }
// ------------------------------------------------------------------------------------------------
MeshGeometry::~MeshGeometry() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& MeshGeometry::GetVertices() const { const std::vector<aiVector3D>& MeshGeometry::GetVertices() const {
return m_vertices; return m_vertices;

View File

@ -55,22 +55,25 @@ namespace FBX {
/** /**
* DOM base class for all kinds of FBX geometry * DOM base class for all kinds of FBX geometry
*/ */
class Geometry : public Object class Geometry : public Object {
{
public: public:
/// @brief The class constructor with all parameters.
/// @param id The id.
/// @param element
/// @param name
/// @param doc
Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc ); Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
virtual ~Geometry(); virtual ~Geometry() = default;
/** Get the Skin attached to this geometry or nullptr */ /// Get the Skin attached to this geometry or nullptr
const Skin* DeformerSkin() const; const Skin* DeformerSkin() const;
/** Get the BlendShape attached to this geometry or nullptr */ /// Get the BlendShape attached to this geometry or nullptr
const std::vector<const BlendShape*>& GetBlendShapes() const; const std::vector<const BlendShape*>& GetBlendShapes() const;
private: private:
const Skin* skin; const Skin* skin;
std::vector<const BlendShape*> blendShapes; std::vector<const BlendShape*> blendShapes;
}; };
typedef std::vector<int> MatIndexArray; typedef std::vector<int> MatIndexArray;
@ -79,14 +82,13 @@ typedef std::vector<int> MatIndexArray;
/** /**
* DOM class for FBX geometry of type "Mesh" * DOM class for FBX geometry of type "Mesh"
*/ */
class MeshGeometry : public Geometry class MeshGeometry : public Geometry {
{
public: public:
/** The class constructor */ /** The class constructor */
MeshGeometry( uint64_t id, const Element& element, const std::string& name, const Document& doc ); MeshGeometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
/** The class destructor */ /** The class destructor */
virtual ~MeshGeometry(); virtual ~MeshGeometry() = default;
/** Get a list of all vertex points, non-unique*/ /** Get a list of all vertex points, non-unique*/
const std::vector<aiVector3D>& GetVertices() const; const std::vector<aiVector3D>& GetVertices() const;
@ -130,6 +132,7 @@ public:
/** Determine the face to which a particular output vertex index belongs. /** Determine the face to which a particular output vertex index belongs.
* This mapping is always unique. */ * This mapping is always unique. */
unsigned int FaceForVertexIndex( unsigned int in_index ) const; unsigned int FaceForVertexIndex( unsigned int in_index ) const;
private: private:
void ReadLayer( const Scope& layer ); void ReadLayer( const Scope& layer );
void ReadLayerElement( const Scope& layerElement ); void ReadLayerElement( const Scope& layerElement );

View File

@ -57,114 +57,65 @@ namespace FBX {
using namespace Util; using namespace Util;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
NodeAttribute::NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name) NodeAttribute::NodeAttribute(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
: Object(id,element,name) Object(id, element, name), props() {
, props() const Scope &sc = GetRequiredScope(element);
{
const Scope& sc = GetRequiredScope(element);
const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2)); const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
// hack on the deriving type but Null/LimbNode attributes are the only case in which // hack on the deriving type but Null/LimbNode attributes are the only case in which
// the property table is by design absent and no warning should be generated // the property table is by design absent and no warning should be generated
// for it. // for it.
const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode"); const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
props = GetPropertyTable(doc,"NodeAttribute.Fbx" + classname,element,sc, is_null_or_limb); props = GetPropertyTable(doc, "NodeAttribute.Fbx" + classname, element, sc, is_null_or_limb);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
NodeAttribute::~NodeAttribute() CameraSwitcher::CameraSwitcher(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
{ NodeAttribute(id, element, doc, name) {
// empty const Scope &sc = GetRequiredScope(element);
} const Element *const CameraId = sc["CameraId"];
const Element *const CameraName = sc["CameraName"];
const Element *const CameraIndexName = sc["CameraIndexName"];
if (CameraId) {
// ------------------------------------------------------------------------------------------------ cameraId = ParseTokenAsInt(GetRequiredToken(*CameraId, 0));
CameraSwitcher::CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: NodeAttribute(id,element,doc,name)
{
const Scope& sc = GetRequiredScope(element);
const Element* const CameraId = sc["CameraId"];
const Element* const CameraName = sc["CameraName"];
const Element* const CameraIndexName = sc["CameraIndexName"];
if(CameraId) {
cameraId = ParseTokenAsInt(GetRequiredToken(*CameraId,0));
} }
if(CameraName) { if (CameraName) {
cameraName = GetRequiredToken(*CameraName,0).StringContents(); cameraName = GetRequiredToken(*CameraName, 0).StringContents();
} }
if(CameraIndexName && CameraIndexName->Tokens().size()) { if (CameraIndexName && CameraIndexName->Tokens().size()) {
cameraIndexName = GetRequiredToken(*CameraIndexName,0).StringContents(); cameraIndexName = GetRequiredToken(*CameraIndexName, 0).StringContents();
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
CameraSwitcher::~CameraSwitcher() Camera::Camera(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
{ NodeAttribute(id, element, doc, name) {
// empty // empty
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Camera::Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name) Light::Light(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
: NodeAttribute(id,element,doc,name) NodeAttribute(id, element, doc, name) {
{
// empty // empty
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Camera::~Camera() Null::Null(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
{ NodeAttribute(id, element, doc, name) {
// empty // empty
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Light::Light(uint64_t id, const Element& element, const Document& doc, const std::string& name) LimbNode::LimbNode(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
: NodeAttribute(id,element,doc,name) NodeAttribute(id, element, doc, name) {
{
// empty // empty
} }
} // namespace FBX
} // namespace Assimp
// ------------------------------------------------------------------------------------------------ #endif // ASSIMP_BUILD_NO_FBX_IMPORTER
Light::~Light()
{
}
// ------------------------------------------------------------------------------------------------
Null::Null(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: NodeAttribute(id,element,doc,name)
{
}
// ------------------------------------------------------------------------------------------------
Null::~Null()
{
}
// ------------------------------------------------------------------------------------------------
LimbNode::LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: NodeAttribute(id,element,doc,name)
{
}
// ------------------------------------------------------------------------------------------------
LimbNode::~LimbNode()
{
}
}
}
#endif

View File

@ -162,12 +162,6 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token)
while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET); while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET);
} }
// ------------------------------------------------------------------------------------------------
Element::~Element()
{
// no need to delete tokens, they are owned by the parser
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Scope::Scope(Parser& parser,bool topLevel) Scope::Scope(Parser& parser,bool topLevel)
{ {
@ -226,12 +220,6 @@ Parser::Parser (const TokenList& tokens, bool is_binary)
root.reset(new Scope(*this,true)); root.reset(new Scope(*this,true));
} }
// ------------------------------------------------------------------------------------------------
Parser::~Parser()
{
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
TokenPtr Parser::AdvanceToNextToken() TokenPtr Parser::AdvanceToNextToken()
{ {
@ -961,8 +949,7 @@ void ParseVectorDataArray(std::vector<float>& out, const Element& el)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read an array of uints // read an array of uints
void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el) void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el) {
{
out.resize( 0 ); out.resize( 0 );
const TokenList& tok = el.Tokens(); const TokenList& tok = el.Tokens();
if(tok.empty()) { if(tok.empty()) {
@ -1186,7 +1173,6 @@ aiMatrix4x4 ReadMatrix(const Element& element)
return result; return result;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// wrapper around ParseTokenAsString() with ParseError handling // wrapper around ParseTokenAsString() with ParseError handling
std::string ParseTokenAsString(const Token& t) std::string ParseTokenAsString(const Token& t)

View File

@ -87,7 +87,7 @@ class Element
{ {
public: public:
Element(const Token& key_token, Parser& parser); Element(const Token& key_token, Parser& parser);
~Element(); ~Element() = default;
const Scope* Compound() const { const Scope* Compound() const {
return compound.get(); return compound.get();
@ -160,7 +160,7 @@ public:
/** Parse given a token list. Does not take ownership of the tokens - /** Parse given a token list. Does not take ownership of the tokens -
* the objects must persist during the entire parser lifetime */ * the objects must persist during the entire parser lifetime */
Parser (const TokenList& tokens,bool is_binary); Parser (const TokenList& tokens,bool is_binary);
~Parser(); ~Parser() = default;
const Scope& GetRootScope() const { const Scope& GetRootScope() const {
return *root.get(); return *root.get();

View File

@ -908,7 +908,7 @@ Ref<Node> FindSkeletonRootJoint(Ref<Skin> &skinRef) {
do { do {
startNodeRef = parentNodeRef; startNodeRef = parentNodeRef;
parentNodeRef = startNodeRef->parent; parentNodeRef = startNodeRef->parent;
} while (!parentNodeRef->jointName.empty()); } while (parentNodeRef && !parentNodeRef->jointName.empty());
return parentNodeRef; return parentNodeRef;
} }

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -97,13 +96,14 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
const aiMatrix4x4 &childTransform = pNode->mChildren[a]->mTransformation; const aiMatrix4x4 &childTransform = pNode->mChildren[a]->mTransformation;
aiVector3D childpos(childTransform.a4, childTransform.b4, childTransform.c4); aiVector3D childpos(childTransform.a4, childTransform.b4, childTransform.c4);
ai_real distanceToChild = childpos.Length(); ai_real distanceToChild = childpos.Length();
if (distanceToChild < 0.0001) if (distanceToChild < ai_epsilon) {
continue; continue;
}
aiVector3D up = aiVector3D(childpos).Normalize(); aiVector3D up = aiVector3D(childpos).Normalize();
aiVector3D orth(1.0, 0.0, 0.0); aiVector3D orth(1.0, 0.0, 0.0);
if (std::fabs(orth * up) > 0.99) if (std::fabs(orth * up) > 0.99) {
orth.Set(0.0, 1.0, 0.0); orth.Set(0.0, 1.0, 0.0);
}
aiVector3D front = (up ^ orth).Normalize(); aiVector3D front = (up ^ orth).Normalize();
aiVector3D side = (front ^ up).Normalize(); aiVector3D side = (front ^ up).Normalize();
@ -183,8 +183,9 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
// add all the vertices to the bone's influences // add all the vertices to the bone's influences
bone->mNumWeights = numVertices; bone->mNumWeights = numVertices;
bone->mWeights = new aiVertexWeight[numVertices]; bone->mWeights = new aiVertexWeight[numVertices];
for (unsigned int a = 0; a < numVertices; a++) for (unsigned int a = 0; a < numVertices; ++a) {
bone->mWeights[a] = aiVertexWeight(vertexStartIndex + a, 1.0); bone->mWeights[a] = aiVertexWeight(vertexStartIndex + a, 1.0);
}
// HACK: (thom) transform all vertices to the bone's local space. Should be done before adding // HACK: (thom) transform all vertices to the bone's local space. Should be done before adding
// them to the array, but I'm tired now and I'm annoyed. // them to the array, but I'm tired now and I'm annoyed.
@ -194,8 +195,9 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
} }
// and finally recurse into the children list // and finally recurse into the children list
for (unsigned int a = 0; a < pNode->mNumChildren; a++) for (unsigned int a = 0; a < pNode->mNumChildren; ++a) {
CreateGeometry(pNode->mChildren[a]); CreateGeometry(pNode->mChildren[a]);
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -135,6 +135,9 @@ ASSIMP_API aiScene::aiScene() :
mNumCameras(0), mNumCameras(0),
mCameras(nullptr), mCameras(nullptr),
mMetaData(nullptr), mMetaData(nullptr),
mName(),
mNumSkeletons(0),
mSkeletons(nullptr),
mPrivate(new Assimp::ScenePrivateData()) { mPrivate(new Assimp::ScenePrivateData()) {
// empty // empty
} }
@ -180,7 +183,8 @@ ASSIMP_API aiScene::~aiScene() {
delete[] mCameras; delete[] mCameras;
aiMetadata::Dealloc(mMetaData); aiMetadata::Dealloc(mMetaData);
mMetaData = nullptr;
delete[] mSkeletons;
delete static_cast<Assimp::ScenePrivateData *>(mPrivate); delete static_cast<Assimp::ScenePrivateData *>(mPrivate);
} }

View File

@ -43,10 +43,10 @@
#include "crypt.h" #include "crypt.h"
#ifdef _WIN32 #ifdef _MSC_VER
# pragma warning(push) # pragma warning(push)
# pragma warning(disable : 4244) # pragma warning(disable : 4244)
#endif // _WIN32 #endif // _MSC_VER
/***************************************************************************/ /***************************************************************************/
@ -164,8 +164,8 @@ int crypthead(const char *passwd, uint8_t *buf, int buf_size, uint32_t *pkeys,
return n; return n;
} }
#ifdef _WIN32 #ifdef _MSC_VER
# pragma warning(pop) # pragma warning(pop)
#endif // _WIN32 #endif // _MSC_VER
/***************************************************************************/ /***************************************************************************/

View File

@ -23,8 +23,10 @@
#ifdef _WIN32 #ifdef _WIN32
# define snprintf _snprintf # define snprintf _snprintf
#ifdef _MSC_VER
# pragma warning(push) # pragma warning(push)
# pragma warning(disable : 4131 4100) # pragma warning(disable : 4131 4100)
#endif
# ifdef __clang__ # ifdef __clang__
# pragma clang diagnostic push # pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunused-parameter" # pragma clang diagnostic ignored "-Wunused-parameter"
@ -357,9 +359,9 @@ void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def)
pzlib_filefunc_def->opaque = NULL; pzlib_filefunc_def->opaque = NULL;
} }
#ifdef _WIN32 #ifdef _MSC_VER
# pragma warning(pop) # pragma warning(pop)
# ifdef __clang__ # ifdef __clang__
# pragma clang diagnostic pop # pragma clang diagnostic pop
# endif # endif
#endif // _WIN32 #endif // _MSC_VER

View File

@ -73,10 +73,10 @@
# define TRYFREE(p) {if (p) free(p);} # define TRYFREE(p) {if (p) free(p);}
#endif #endif
#ifdef _WIN32 #ifdef _MSC_VER
# pragma warning(push) # pragma warning(push)
# pragma warning(disable : 4131 4244 4189 4245) # pragma warning(disable : 4131 4244 4189 4245)
#endif // _WIN32 #endif // _MSC_VER
const char unz_copyright[] = const char unz_copyright[] =
" unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
@ -1995,6 +1995,6 @@ extern int ZEXPORT unzEndOfFile(unzFile file)
return 0; return 0;
} }
#ifdef _WIN32 #ifdef _MSC_VER
# pragma warning(pop) # pragma warning(pop)
#endif // _WIN32 #endif // _MSC_VER

View File

@ -691,6 +691,15 @@ enum aiComponent
#define AI_CONFIG_FBX_CONVERT_TO_M \ #define AI_CONFIG_FBX_CONVERT_TO_M \
"AI_CONFIG_FBX_CONVERT_TO_M" "AI_CONFIG_FBX_CONVERT_TO_M"
// ---------------------------------------------------------------------------
/** @brief Will enable the skeleton structo to store bone data.
*
* This will decouple the bone coupling to the mesh. This feature is
* experimental.
*/
#define AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER \
"AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER"
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** @brief Set the vertex animation keyframe to be imported /** @brief Set the vertex animation keyframe to be imported
* *

View File

@ -120,7 +120,7 @@ extern "C" {
* primitive are actually present in a mesh. The #aiProcess_SortByPType flag * primitive are actually present in a mesh. The #aiProcess_SortByPType flag
* executes a special post-processing algorithm which splits meshes with * executes a special post-processing algorithm which splits meshes with
* *different* primitive types mixed up (e.g. lines and triangles) in several * *different* primitive types mixed up (e.g. lines and triangles) in several
* 'clean' submeshes. Furthermore there is a configuration option ( * 'clean' sub-meshes. Furthermore there is a configuration option (
* #AI_CONFIG_PP_SBP_REMOVE) to force #aiProcess_SortByPType to remove * #AI_CONFIG_PP_SBP_REMOVE) to force #aiProcess_SortByPType to remove
* specific kinds of primitives from the imported scene, completely and forever. * specific kinds of primitives from the imported scene, completely and forever.
* In many cases you'll probably want to set this setting to * In many cases you'll probably want to set this setting to
@ -269,12 +269,12 @@ struct aiBone {
unsigned int mNumWeights; unsigned int mNumWeights;
#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS #ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
// The bone armature node - used for skeleton conversion /// The bone armature node - used for skeleton conversion
// you must enable aiProcess_PopulateArmatureData to populate this /// you must enable aiProcess_PopulateArmatureData to populate this
C_STRUCT aiNode *mArmature; C_STRUCT aiNode *mArmature;
// The bone node in the scene - used for skeleton conversion /// The bone node in the scene - used for skeleton conversion
// you must enable aiProcess_PopulateArmatureData to populate this /// you must enable aiProcess_PopulateArmatureData to populate this
C_STRUCT aiNode *mNode; C_STRUCT aiNode *mNode;
#endif #endif
@ -296,7 +296,7 @@ struct aiBone {
#ifdef __cplusplus #ifdef __cplusplus
//! Default constructor /// @brief Default constructor
aiBone() AI_NO_EXCEPT aiBone() AI_NO_EXCEPT
: mName(), : mName(),
mNumWeights(0), mNumWeights(0),
@ -309,7 +309,7 @@ struct aiBone {
// empty // empty
} }
//! Copy constructor /// @brief Copy constructor
aiBone(const aiBone &other) : aiBone(const aiBone &other) :
mName(other.mName), mName(other.mName),
mNumWeights(other.mNumWeights), mNumWeights(other.mNumWeights),
@ -319,14 +319,27 @@ struct aiBone {
#endif #endif
mWeights(nullptr), mWeights(nullptr),
mOffsetMatrix(other.mOffsetMatrix) { mOffsetMatrix(other.mOffsetMatrix) {
if (other.mWeights && other.mNumWeights) { copyVertexWeights(other);
mWeights = new aiVertexWeight[mNumWeights]; }
::memcpy(mWeights, other.mWeights, mNumWeights * sizeof(aiVertexWeight));
void copyVertexWeights( const aiBone &other ) {
if (other.mWeights == nullptr || other.mNumWeights == 0) {
mWeights = nullptr;
mNumWeights = 0;
return;
} }
mNumWeights = other.mNumWeights;
if (mWeights) {
delete[] mWeights;
}
mWeights = new aiVertexWeight[mNumWeights];
::memcpy(mWeights, other.mWeights, mNumWeights * sizeof(aiVertexWeight));
} }
//! Assignment operator //! Assignment operator
aiBone &operator=(const aiBone &other) { aiBone &operator = (const aiBone &other) {
if (this == &other) { if (this == &other) {
return *this; return *this;
} }
@ -334,21 +347,13 @@ struct aiBone {
mName = other.mName; mName = other.mName;
mNumWeights = other.mNumWeights; mNumWeights = other.mNumWeights;
mOffsetMatrix = other.mOffsetMatrix; mOffsetMatrix = other.mOffsetMatrix;
copyVertexWeights(other);
if (other.mWeights && other.mNumWeights) {
if (mWeights) {
delete[] mWeights;
}
mWeights = new aiVertexWeight[mNumWeights];
::memcpy(mWeights, other.mWeights, mNumWeights * sizeof(aiVertexWeight));
}
return *this; return *this;
} }
bool operator==(const aiBone &rhs) const { bool operator==(const aiBone &rhs) const {
if (mName != rhs.mName || mNumWeights != rhs.mNumWeights) { if (mName != rhs.mName || mNumWeights != rhs.mNumWeights ) {
return false; return false;
} }
@ -937,6 +942,100 @@ struct aiMesh {
#endif // __cplusplus #endif // __cplusplus
}; };
struct aiSkeletonBone {
/// The parent bone index, is -1 one if this bone represents the root bone.
int mParent;
#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
/// The bone armature node - used for skeleton conversion
/// you must enable aiProcess_PopulateArmatureData to populate this
C_STRUCT aiNode *mArmature;
/// The bone node in the scene - used for skeleton conversion
/// you must enable aiProcess_PopulateArmatureData to populate this
C_STRUCT aiNode *mNode;
#endif
/// @brief The number of weights
unsigned int mNumnWeights;
/// The mesh index, which will get influenced by the weight.
C_STRUCT aiMesh *mMeshId;
/// The influence weights of this bone, by vertex index.
C_STRUCT aiVertexWeight *mWeights;
/** Matrix that transforms from bone space to mesh space in bind pose.
*
* This matrix describes the position of the mesh
* in the local space of this bone when the skeleton was bound.
* Thus it can be used directly to determine a desired vertex position,
* given the world-space transform of the bone when animated,
* and the position of the vertex in mesh space.
*
* It is sometimes called an inverse-bind matrix,
* or inverse bind pose matrix.
*/
C_STRUCT aiMatrix4x4 mOffsetMatrix;
/// Matrix that transforms the locale bone in bind pose.
C_STRUCT aiMatrix4x4 mLocalMatrix;
#ifdef __cplusplus
aiSkeletonBone() :
mParent(-1),
mArmature(nullptr),
mNode(nullptr),
mNumnWeights(0),
mMeshId(nullptr),
mWeights(nullptr),
mOffsetMatrix(),
mLocalMatrix() {
// empty
}
~aiSkeletonBone() {
delete[] mWeights;
mWeights = nullptr;
}
#endif // __cplusplus
};
/**
* @brief
*/
struct aiSkeleton {
/**
*
*/
C_STRUCT aiString mName;
/**
*
*/
unsigned int mNumBones;
/**
*
*/
C_STRUCT aiSkeletonBone **mBones;
#ifdef __cplusplus
/**
*
*/
aiSkeleton() AI_NO_EXCEPT : mName(), mNumBones(0), mBones(nullptr) {
// empty
}
/**
*
*/
~aiSkeleton() {
delete[] mBones;
}
#endif // __cplusplus
};
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif //! extern "C" #endif //! extern "C"

View File

@ -79,8 +79,7 @@ extern "C" {
* the imported scene does consist of only a single root node without children. * the imported scene does consist of only a single root node without children.
*/ */
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
struct ASSIMP_API aiNode struct ASSIMP_API aiNode {
{
/** The name of the node. /** The name of the node.
* *
* The name might be empty (length of zero) but all nodes which * The name might be empty (length of zero) but all nodes which
@ -343,6 +342,16 @@ struct aiScene
*/ */
C_STRUCT aiString mName; C_STRUCT aiString mName;
/**
*
*/
unsigned int mNumSkeletons;
/**
*
*/
C_STRUCT aiSkeleton **mSkeletons;
#ifdef __cplusplus #ifdef __cplusplus
//! Default constructor - set everything to 0/nullptr //! Default constructor - set everything to 0/nullptr
@ -383,6 +392,10 @@ struct aiScene
return mAnimations != nullptr && mNumAnimations > 0; return mAnimations != nullptr && mNumAnimations > 0;
} }
bool hasSkeletons() const {
return mSkeletons != nullptr && mNumSkeletons > 0;
}
//! Returns a short filename from a full path //! Returns a short filename from a full path
static const char* GetShortFilename(const char* filename) { static const char* GetShortFilename(const char* filename) {
const char* lastSlash = strrchr(filename, '/'); const char* lastSlash = strrchr(filename, '/');

Binary file not shown.

View File

@ -423,3 +423,10 @@ TEST_F(utFBXImporterExporter, importMaxPbrMaterialsSpecularGloss) {
ASSERT_EQ(mat->Get("$raw.3dsMax|main|emit_color", aiTextureType_NONE, 0, emitColor), aiReturn_SUCCESS); ASSERT_EQ(mat->Get("$raw.3dsMax|main|emit_color", aiTextureType_NONE, 0, emitColor), aiReturn_SUCCESS);
EXPECT_EQ(emitColor, aiColor4D(1, 0, 1, 1)); EXPECT_EQ(emitColor, aiColor4D(1, 0, 1, 1));
} }
TEST_F(utFBXImporterExporter, importSkeletonTest) {
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/animation_with_skeleton.fbx", aiProcess_ValidateDataStructure);
ASSERT_NE(nullptr, scene);
ASSERT_TRUE(scene->mRootNode);
}