Merge pull request #4552 from assimp/kimkulling/create_skeleton_data_issue_4015

[Experimental] New skeleton container for bones
pull/4577/head
Kim Kulling 2022-06-11 21:57:41 +02:00 committed by GitHub
commit b8812d2b4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 405 additions and 296 deletions

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team
All rights reserved.
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,
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);
}
// ------------------------------------------------------------------------------------------------
AnimationCurveNode::~AnimationCurveNode() {
// empty
}
// ------------------------------------------------------------------------------------------------
const AnimationCurveMap &AnimationCurveNode::Curves() const {
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);
}
// ------------------------------------------------------------------------------------------------
AnimationLayer::~AnimationLayer() {
// empty
}
// ------------------------------------------------------------------------------------------------
AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_prop_whitelist /*= nullptr*/,
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 Assimp

View File

@ -50,7 +50,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp {
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'
}; // 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
All rights reserved.
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 <cstdint>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <memory>
#include <sstream>
#include <tuple>
#include <vector>
namespace Assimp {
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.
/// 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(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {}
aiNode* operator->() { return mNode; }
@ -231,7 +227,7 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
if (nullptr != model) {
nodes_chain.clear();
post_nodes_chain.clear();
aiMatrix4x4 new_abs_transform = parent->mTransformation;
std::string node_name = FixNodeName(model->Name());
// even though there is only a single input node, the design of
// 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
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
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
unsigned int &i = it_pair.first->second;
while (!it_pair.second) {
i++;
++i;
std::ostringstream ext;
ext << name << std::setfill('0') << std::setw(3) << i;
uniqueName = ext.str();
@ -646,7 +642,6 @@ void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D &rot
bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
const PropertyTable &props = model.Props();
bool ok;
const auto zero_epsilon = ai_epsilon;
const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
@ -660,6 +655,7 @@ bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
bool scale_compare = (comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling);
bool ok = true;
const aiVector3D &v = PropertyGet<aiVector3D>(props, NameTransformationCompProperty(comp), ok);
if (ok && scale_compare) {
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();
std::vector<unsigned int> meshes;
meshes.reserve(geos.size());
for (const Geometry *geo : geos) {
const MeshGeometry *const mesh = dynamic_cast<const MeshGeometry *>(geo);
const LineGeometry *const line = dynamic_cast<const LineGeometry *>(geo);
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));
} else if (line) {
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>
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;
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];
for (MatIndexArray::value_type index : mindices) {
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
temp.push_back(ConvertMeshSingleMaterial(mesh, model, parent, root_node));
temp.push_back(ConvertMeshSingleMaterial(mesh, model, absolute_transform, parent, root_node));
return temp;
}
@ -1023,7 +1018,35 @@ aiMesh *FBXConverter::SetupEmptyMesh(const Geometry &mesh, aiNode *parent) {
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 *) {
const MatIndexArray &mindices = mesh.GetMaterialIndices();
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]);
}
if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr) {
ConvertWeights(out_mesh, mesh, parent, NO_MATERIAL_SEPARATION, nullptr);
if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr && !doc.Settings().useSkeleton) {
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;
@ -1190,7 +1220,7 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
}
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) {
const MatIndexArray &mindices = mesh.GetMaterialIndices();
ai_assert(mindices.size());
@ -1201,7 +1231,7 @@ FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &mo
for (MatIndexArray::value_type index : mindices) {
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);
}
}
@ -1209,9 +1239,8 @@ FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &mo
return indices;
}
unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model,
MatIndexArray::value_type index,
aiNode *parent, aiNode *) {
unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform,
MatIndexArray::value_type index, aiNode *parent, aiNode *) {
aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent);
const MatIndexArray &mindices = mesh.GetMaterialIndices();
@ -1374,7 +1403,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
ConvertMaterialForMesh(out_mesh, model, mesh, index);
if (process_weights) {
ConvertWeights(out_mesh, mesh, parent, index, &reverseMapping);
ConvertWeights(out_mesh, mesh, absolute_transform, parent, index, &reverseMapping);
}
std::vector<aiAnimMesh *> animMeshes;
@ -1424,19 +1453,47 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
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,
std::vector<unsigned int> *outputVertStartIndices) {
ai_assert(geo.DeformerSkin());
std::vector<size_t> out_indices;
std::vector<size_t> index_out_indices;
std::vector<size_t> count_out_indices;
std::vector<size_t> out_indices, index_out_indices, count_out_indices;
const Skin &sk = *geo.DeformerSkin();
std::vector<aiBone *> bones;
std::vector<aiBone*> bones;
const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION;
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
// data in a single step.
ConvertCluster(bones, cluster, out_indices, index_out_indices,
count_out_indices, parent);
count_out_indices, absolute_transform, parent);
}
bone_map.clear();
@ -1509,25 +1566,20 @@ void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo,
out->mBones = nullptr;
out->mNumBones = 0;
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);
}
}
const aiNode *GetNodeByName(aiNode *current_node) {
aiNode *iter = current_node;
//printf("Child count: %d", iter->mNumChildren);
return iter;
}
void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
void FBXConverter::ConvertCluster(std::vector<aiBone*> &local_mesh_bones, const Cluster *cluster,
std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
std::vector<size_t> &count_out_indices, aiNode *) {
ai_assert(cl); // make sure cluster valid
std::string deformer_name = cl->TargetNode()->Name();
std::vector<size_t> &count_out_indices, const aiMatrix4x4 & /* absolute_transform*/,
aiNode *) {
ai_assert(cluster != nullptr); // make sure cluster valid
std::string deformer_name = cluster->TargetNode()->Name();
aiString bone_name = aiString(FixNodeName(deformer_name));
aiBone *bone = nullptr;
@ -1540,10 +1592,10 @@ void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const
bone = new aiBone();
bone->mName = bone_name;
bone->mOffsetMatrix = cl->Transform();
bone->mOffsetMatrix = cluster->Transform();
// store local transform link for post processing
/*
bone->mOffsetMatrix = cl->TransformLink();
bone->mOffsetMatrix = cluster->TransformLink();
bone->mOffsetMatrix.Inverse();
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()];
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();
for (size_t i = 0; i < c; ++i) {
@ -2605,7 +2657,7 @@ void FBXConverter::ConvertAnimationStack(const AnimationStack &st) {
meshMorphAnim->mNumKeys = numKeys;
meshMorphAnim->mKeys = new aiMeshMorphKey[numKeys];
unsigned int j = 0;
for (auto animIt : *animData) {
for (auto &animIt : *animData) {
morphKeyData *keyData = animIt.second;
unsigned int numValuesAndWeights = static_cast<unsigned int>(keyData->values.size());
meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights;
@ -3625,6 +3677,12 @@ void FBXConverter::TransferDataToScene() {
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() {

View File

@ -75,7 +75,18 @@ typedef std::map<int64_t, morphKeyData*> morphAnimData;
namespace Assimp {
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;
/**
* Convert a FBX #Document to #aiScene
* @param out Empty scene to be populated
@ -180,12 +191,12 @@ private:
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
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);
@ -194,15 +205,15 @@ private:
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);
// ------------------------------------------------------------------------------------------------
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);
// ------------------------------------------------------------------------------------------------
@ -216,14 +227,19 @@ private:
* - outputVertStartIndices is only used when a material index is specified, it gives for
* 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,
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,
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,
@ -296,7 +312,8 @@ private:
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,
@ -445,6 +462,7 @@ private:
double anim_fps;
std::vector<aiSkeleton *> mSkeletons;
aiScene* const mSceneOut;
const FBX::Document& doc;
bool mRemoveEmptyBones;

View File

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

View File

@ -544,7 +544,7 @@ std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bo
ai_assert( count != 0 );
ai_assert( count <= MAX_CLASSNAMES);
size_t lengths[MAX_CLASSNAMES];
size_t lengths[MAX_CLASSNAMES] = {};
const size_t c = count;
for (size_t i = 0; i < c; ++i) {

View File

@ -164,7 +164,7 @@ class NodeAttribute : public Object {
public:
NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name);
virtual ~NodeAttribute();
virtual ~NodeAttribute() = default;
const PropertyTable& Props() const {
ai_assert(props.get());
@ -180,7 +180,7 @@ class CameraSwitcher : public NodeAttribute {
public:
CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name);
virtual ~CameraSwitcher();
virtual ~CameraSwitcher() = default;
int CameraID() const {
return cameraId;
@ -225,7 +225,7 @@ class Camera : public NodeAttribute {
public:
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(UpVector, aiVector3D, aiVector3D(0,1,0))
@ -250,21 +250,21 @@ public:
class Null : public NodeAttribute {
public:
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 */
class LimbNode : public NodeAttribute {
public:
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 */
class Light : public NodeAttribute {
public:
Light(uint64_t id, const Element& element, const Document& doc, const std::string& name);
virtual ~Light();
virtual ~Light() = default;
enum Type {
Type_Point,
@ -690,7 +690,7 @@ using KeyValueList = std::vector<float>;
class AnimationCurve : public Object {
public:
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).
* Invariant: |GetKeys()| > 0 */
@ -731,7 +731,7 @@ public:
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);
virtual ~AnimationCurveNode();
virtual ~AnimationCurveNode() = default;
const PropertyTable& Props() const {
ai_assert(props.get());
@ -776,7 +776,7 @@ using AnimationCurveNodeList = std::vector<const AnimationCurveNode*>;
class AnimationLayer : public Object {
public:
AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc);
virtual ~AnimationLayer();
virtual ~AnimationLayer() = default;
const PropertyTable& Props() const {
ai_assert(props.get());
@ -799,7 +799,7 @@ using AnimationLayerList = std::vector<const AnimationLayer*>;
class AnimationStack : public Object {
public:
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(LocalStop, int64_t, 0L)

View File

@ -59,14 +59,12 @@ namespace Util {
// ------------------------------------------------------------------------------------------------
// 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);
}
// ------------------------------------------------------------------------------------------------
void DOMError(const std::string& message, const Element* element /*= nullptr*/)
{
void DOMError(const std::string& message, const Element* element /*= nullptr*/) {
if(element) {
DOMError(message,element->KeyToken());
}
@ -76,8 +74,7 @@ void DOMError(const std::string& message, const Element* element /*= nullptr*/)
// ------------------------------------------------------------------------------------------------
// 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()) {
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>
inline
const T* ProcessSimpleConnection(const Connection& con,
inline const T* ProcessSimpleConnection(const Connection& con,
bool is_object_property_conn,
const char* name,
const Element& element,
const char** propNameOut = nullptr)
{
const char** propNameOut = nullptr) {
if (is_object_property_conn && !con.PropertyName().length()) {
DOMWarning("expected incoming " + std::string(name) +
" link to be an object-object connection, ignoring",

View File

@ -255,7 +255,7 @@ void FBXExporter::WriteBinaryHeader()
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);

View File

@ -60,6 +60,7 @@ struct ImportSettings {
readLights(true),
readAnimations(true),
readWeights(true),
useSkeleton(false),
preservePivots(true),
optimizeEmptyAnimationCurves(true),
useLegacyEmbeddedTextureNaming(false),
@ -112,6 +113,11 @@ struct ImportSettings {
* Default value is true. */
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
* not directly be represented in assimp, additional dummy
* 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
FBXImporter::FBXImporter() {
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
FBXImporter::~FBXImporter() {
FBXImporter::FBXImporter() :
mSettings() {
// empty
}
// ------------------------------------------------------------------------------------------------
@ -115,20 +112,21 @@ const aiImporterDesc *FBXImporter::GetInfo() const {
// ------------------------------------------------------------------------------------------------
// Setup configuration properties for the loader
void FBXImporter::SetupProperties(const Importer *pImp) {
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
settings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
settings.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);
settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
mSettings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
mSettings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
mSettings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
mSettings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
mSettings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
mSettings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
mSettings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
mSettings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
mSettings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
mSettings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
mSettings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
mSettings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
mSettings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
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;
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)
TokenList tokens;
try {
@ -173,15 +171,14 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
Parser parser(tokens, is_binary);
// 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
ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones);
ConvertToAssimpScene(pScene, doc, mSettings.removeEmptyBones);
// size relative to cm
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.
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> {
public:
/// @brief The class constructor.
FBXImporter();
~FBXImporter() override;
// --------------------
bool CanRead(const std::string &pFile,
IOSystem *pIOHandler,
bool checkSig) const override;
/// @brief The class destructor, default implementation.
~FBXImporter() override = default;
/// @brief Will check the file for readability.
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
protected:
// --------------------
@ -90,7 +91,7 @@ protected:
IOSystem *pIOHandler) override;
private:
FBX::ImportSettings settings;
FBX::ImportSettings mSettings;
}; // !class FBXImporter
} // end of namespace Assimp

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team
All rights reserved.
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 "FBXDocumentUtil.h"
namespace Assimp {
namespace FBX {
using namespace Util;
// ------------------------------------------------------------------------------------------------
Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
: Object(id, element, name)
, skin()
{
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) :
Object(id, element, name), skin() {
const std::vector<const Connection*> &conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
for(const Connection* con : conns) {
const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
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 {
return blendShapes;
@ -183,18 +173,12 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
if(doc.Settings().readAllLayers || index == 0) {
const Scope& layer = GetRequiredScope(*(*it).second);
ReadLayer(layer);
}
else {
} else {
FBXImporter::LogWarn("ignoring additional geometry layers");
}
}
}
// ------------------------------------------------------------------------------------------------
MeshGeometry::~MeshGeometry() {
// empty
}
// ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& MeshGeometry::GetVertices() const {
return m_vertices;

View File

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

View File

@ -57,114 +57,65 @@ namespace FBX {
using namespace Util;
// ------------------------------------------------------------------------------------------------
NodeAttribute::NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: Object(id,element,name)
, props()
{
const Scope& sc = GetRequiredScope(element);
NodeAttribute::NodeAttribute(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
Object(id, element, name), props() {
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
// the property table is by design absent and no warning should be generated
// for it.
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()
{
// empty
}
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"];
// ------------------------------------------------------------------------------------------------
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 (CameraId) {
cameraId = ParseTokenAsInt(GetRequiredToken(*CameraId, 0));
}
if(CameraName) {
cameraName = GetRequiredToken(*CameraName,0).StringContents();
if (CameraName) {
cameraName = GetRequiredToken(*CameraName, 0).StringContents();
}
if(CameraIndexName && CameraIndexName->Tokens().size()) {
cameraIndexName = GetRequiredToken(*CameraIndexName,0).StringContents();
if (CameraIndexName && CameraIndexName->Tokens().size()) {
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
}
// ------------------------------------------------------------------------------------------------
Camera::Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: NodeAttribute(id,element,doc,name)
{
Light::Light(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
NodeAttribute(id, element, doc, name) {
// empty
}
// ------------------------------------------------------------------------------------------------
Camera::~Camera()
{
Null::Null(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
NodeAttribute(id, element, doc, name) {
// empty
}
// ------------------------------------------------------------------------------------------------
Light::Light(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: NodeAttribute(id,element,doc,name)
{
LimbNode::LimbNode(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
NodeAttribute(id, element, doc, name) {
// empty
}
} // namespace FBX
} // namespace Assimp
// ------------------------------------------------------------------------------------------------
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
#endif // ASSIMP_BUILD_NO_FBX_IMPORTER

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);
}
// ------------------------------------------------------------------------------------------------
Element::~Element()
{
// no need to delete tokens, they are owned by the parser
}
// ------------------------------------------------------------------------------------------------
Scope::Scope(Parser& parser,bool topLevel)
{
@ -226,12 +220,6 @@ Parser::Parser (const TokenList& tokens, bool is_binary)
root.reset(new Scope(*this,true));
}
// ------------------------------------------------------------------------------------------------
Parser::~Parser()
{
// empty
}
// ------------------------------------------------------------------------------------------------
TokenPtr Parser::AdvanceToNextToken()
{
@ -961,8 +949,7 @@ void ParseVectorDataArray(std::vector<float>& out, const Element& el)
// ------------------------------------------------------------------------------------------------
// 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 );
const TokenList& tok = el.Tokens();
if(tok.empty()) {
@ -1186,7 +1173,6 @@ aiMatrix4x4 ReadMatrix(const Element& element)
return result;
}
// ------------------------------------------------------------------------------------------------
// wrapper around ParseTokenAsString() with ParseError handling
std::string ParseTokenAsString(const Token& t)

View File

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

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team
All rights reserved.
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;
aiVector3D childpos(childTransform.a4, childTransform.b4, childTransform.c4);
ai_real distanceToChild = childpos.Length();
if (distanceToChild < 0.0001)
if (distanceToChild < ai_epsilon) {
continue;
}
aiVector3D up = aiVector3D(childpos).Normalize();
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);
}
aiVector3D front = (up ^ orth).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
bone->mNumWeights = 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);
}
// 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.
@ -194,8 +195,9 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
}
// 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]);
}
}
// ------------------------------------------------------------------------------------------------

View File

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

View File

@ -691,6 +691,15 @@ enum aiComponent
#define 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
*

View File

@ -120,7 +120,7 @@ extern "C" {
* primitive are actually present in a mesh. The #aiProcess_SortByPType flag
* executes a special post-processing algorithm which splits meshes with
* *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
* specific kinds of primitives from the imported scene, completely and forever.
* In many cases you'll probably want to set this setting to
@ -269,12 +269,12 @@ struct aiBone {
unsigned int mNumWeights;
#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
// The bone armature node - used for skeleton conversion
// you must enable aiProcess_PopulateArmatureData to populate this
/// 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
/// The bone node in the scene - used for skeleton conversion
/// you must enable aiProcess_PopulateArmatureData to populate this
C_STRUCT aiNode *mNode;
#endif
@ -296,7 +296,7 @@ struct aiBone {
#ifdef __cplusplus
//! Default constructor
/// @brief Default constructor
aiBone() AI_NO_EXCEPT
: mName(),
mNumWeights(0),
@ -309,7 +309,7 @@ struct aiBone {
// empty
}
//! Copy constructor
/// @brief Copy constructor
aiBone(const aiBone &other) :
mName(other.mName),
mNumWeights(other.mNumWeights),
@ -319,23 +319,17 @@ struct aiBone {
#endif
mWeights(nullptr),
mOffsetMatrix(other.mOffsetMatrix) {
if (other.mWeights && other.mNumWeights) {
mWeights = new aiVertexWeight[mNumWeights];
::memcpy(mWeights, other.mWeights, mNumWeights * sizeof(aiVertexWeight));
}
copyVertexWeights(other);
}
//! Assignment operator
aiBone &operator=(const aiBone &other) {
if (this == &other) {
return *this;
void copyVertexWeights( const aiBone &other ) {
if (other.mWeights == nullptr || other.mNumWeights == 0) {
mWeights = nullptr;
mNumWeights = 0;
return;
}
mName = other.mName;
mNumWeights = other.mNumWeights;
mOffsetMatrix = other.mOffsetMatrix;
if (other.mWeights && other.mNumWeights) {
if (mWeights) {
delete[] mWeights;
}
@ -344,11 +338,22 @@ struct aiBone {
::memcpy(mWeights, other.mWeights, mNumWeights * sizeof(aiVertexWeight));
}
//! Assignment operator
aiBone &operator = (const aiBone &other) {
if (this == &other) {
return *this;
}
mName = other.mName;
mNumWeights = other.mNumWeights;
mOffsetMatrix = other.mOffsetMatrix;
copyVertexWeights(other);
return *this;
}
bool operator==(const aiBone &rhs) const {
if (mName != rhs.mName || mNumWeights != rhs.mNumWeights) {
if (mName != rhs.mName || mNumWeights != rhs.mNumWeights ) {
return false;
}
@ -937,6 +942,100 @@ struct aiMesh {
#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
}
#endif //! extern "C"

View File

@ -79,8 +79,7 @@ extern "C" {
* 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 might be empty (length of zero) but all nodes which
@ -343,6 +342,16 @@ struct aiScene
*/
C_STRUCT aiString mName;
/**
*
*/
unsigned int mNumSkeletons;
/**
*
*/
C_STRUCT aiSkeleton **mSkeletons;
#ifdef __cplusplus
//! Default constructor - set everything to 0/nullptr
@ -383,6 +392,10 @@ struct aiScene
return mAnimations != nullptr && mNumAnimations > 0;
}
bool hasSkeletons() const {
return mSkeletons != nullptr && mNumSkeletons > 0;
}
//! Returns a short filename from a full path
static const char* GetShortFilename(const char* 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);
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);
}