Skip to content

Commit

Permalink
Merge pull request #2469 from muxanickms/topic/fbx_node_naming_optimi…
Browse files Browse the repository at this point in the history
…zation

Node names optimization and fixing non-unique name
  • Loading branch information
kimkulling committed May 24, 2019
2 parents f0a0de6 + e1ed975 commit 4feefaf
Show file tree
Hide file tree
Showing 6 changed files with 2,734 additions and 51 deletions.
101 changes: 55 additions & 46 deletions code/FBXConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ namespace Assimp {
, textures_converted()
, meshes_converted()
, node_anim_chain_bits()
, mNodeNameInstances()
, mNodeNames()
, anim_fps()
, out(out)
Expand Down Expand Up @@ -142,12 +141,46 @@ namespace Assimp {

void FBXConverter::ConvertRootNode() {
out->mRootNode = new aiNode();
out->mRootNode->mName.Set("RootNode");
std::string unique_name;
GetUniqueName("RootNode", unique_name);
out->mRootNode->mName.Set(unique_name);

// root has ID 0
ConvertNodes(0L, *out->mRootNode);
}

static std::string getAncestorBaseName(const aiNode* node)
{
const char* nodeName = nullptr;
size_t length = 0;
while (node && (!nodeName || length == 0))
{
nodeName = node->mName.C_Str();
length = node->mName.length;
node = node->mParent;
}

if (!nodeName || length == 0)
{
return {};
}
// could be std::string_view if c++17 available
return std::string(nodeName, length);
}

// Make unique name
std::string FBXConverter::MakeUniqueNodeName(const Model* const model, const aiNode& parent)
{
std::string original_name = FixNodeName(model->Name());
if (original_name.empty())
{
original_name = getAncestorBaseName(&parent);
}
std::string unique_name;
GetUniqueName(original_name, unique_name);
return unique_name;
}

void FBXConverter::ConvertNodes(uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform) {
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(id, "Model");

Expand Down Expand Up @@ -179,35 +212,18 @@ namespace Assimp {

aiMatrix4x4 new_abs_transform = parent_transform;

std::string unique_name = MakeUniqueNodeName(model, parent);

// even though there is only a single input node, the design of
// assimp (or rather: the complicated transformation chain that
// is employed by fbx) means that we may need multiple aiNode's
// to represent a fbx node's transformation.
GenerateTransformationNodeChain(*model, nodes_chain, post_nodes_chain);
const bool need_additional_node = GenerateTransformationNodeChain(*model, unique_name, nodes_chain, post_nodes_chain);

ai_assert(nodes_chain.size());

std::string original_name = FixNodeName(model->Name());

// check if any of the nodes in the chain has the name the fbx node
// is supposed to have. If there is none, add another node to
// preserve the name - people might have scripts etc. that rely
// on specific node names.
aiNode* name_carrier = NULL;
for (aiNode* prenode : nodes_chain) {
if (!strcmp(prenode->mName.C_Str(), original_name.c_str())) {
name_carrier = prenode;
break;
}
}

if (!name_carrier) {
std::string old_original_name = original_name;
GetUniqueName(old_original_name, original_name);
nodes_chain.push_back(new aiNode(original_name));
}
else {
original_name = nodes_chain.back()->mName.C_Str();
if (need_additional_node) {
nodes_chain.push_back(new aiNode(unique_name));
}

//setup metadata on newest node
Expand Down Expand Up @@ -269,11 +285,11 @@ namespace Assimp {
ConvertNodes(model->ID(), *last_parent, new_abs_transform);

if (doc.Settings().readLights) {
ConvertLights(*model, original_name);
ConvertLights(*model, unique_name);
}

if (doc.Settings().readCameras) {
ConvertCameras(*model, original_name);
ConvertCameras(*model, unique_name);
}

nodes.push_back(nodes_chain.front());
Expand Down Expand Up @@ -426,21 +442,16 @@ namespace Assimp {
void FBXConverter::GetUniqueName(const std::string &name, std::string &uniqueName)
{
uniqueName = name;
int i = 0;
auto it = mNodeNameInstances.find(name); // duplicate node name instance count
if (it != mNodeNameInstances.end())
auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count
unsigned int& i = it_pair.first->second;
while (!it_pair.second)
{
i = it->second;
while (mNodeNames.find(uniqueName) != mNodeNames.end())
{
i++;
std::stringstream ext;
ext << name << std::setfill('0') << std::setw(3) << i;
uniqueName = ext.str();
}
i++;
std::ostringstream ext;
ext << name << std::setfill('0') << std::setw(3) << i;
uniqueName = ext.str();
it_pair = mNodeNames.insert({ uniqueName, 0 });
}
mNodeNameInstances[name] = i;
mNodeNames.insert(uniqueName);
}

const char* FBXConverter::NameTransformationComp(TransformationComp comp) {
Expand Down Expand Up @@ -672,7 +683,7 @@ namespace Assimp {
return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp);
}

void FBXConverter::GenerateTransformationNodeChain(const Model& model, std::vector<aiNode*>& output_nodes,
bool FBXConverter::GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<aiNode*>& output_nodes,
std::vector<aiNode*>& post_output_nodes) {
const PropertyTable& props = model.Props();
const Model::RotOrder rot = model.RotationOrder();
Expand Down Expand Up @@ -787,8 +798,6 @@ namespace Assimp {
// not be guaranteed.
ai_assert(NeedsComplexTransformationChain(model) == is_complex);

std::string name = FixNodeName(model.Name());

// now, if we have more than just Translation, Scaling and Rotation,
// we need to generate a full node chain to accommodate for assimp's
// lack to express pivots and offsets.
Expand Down Expand Up @@ -830,20 +839,20 @@ namespace Assimp {
}

ai_assert(output_nodes.size());
return;
return true;
}

// else, we can just multiply the matrices together
aiNode* nd = new aiNode();
output_nodes.push_back(nd);
std::string uniqueName;
GetUniqueName(name, uniqueName);

nd->mName.Set(uniqueName);
// name passed to the method is already unique
nd->mName.Set(name);

for (const auto &transform : chain) {
nd->mTransformation = nd->mTransformation * transform;
}
return false;
}

void FBXConverter::SetupNodeMetadata(const Model& model, aiNode& nd)
Expand Down
12 changes: 7 additions & 5 deletions code/FBXConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@ class FBXConverter {
// while these would be allowed, they are a potential trouble spot so better not use them).
const char* NameTransformationComp(TransformationComp comp);

// ------------------------------------------------------------------------------------------------
// Returns an unique name for a node or traverses up a hierarchy until a non-empty name is found and
// then makes this name unique
std::string MakeUniqueNodeName(const Model* const model, const aiNode& parent);

// ------------------------------------------------------------------------------------------------
// note: this returns the REAL fbx property names
const char* NameTransformationCompProperty(TransformationComp comp);
Expand All @@ -177,7 +182,7 @@ class FBXConverter {
/**
* note: memory for output_nodes will be managed by the caller
*/
void GenerateTransformationNodeChain(const Model& model, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes);
bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes);

// ------------------------------------------------------------------------------------------------
void SetupNodeMetadata(const Model& model, aiNode& nd);
Expand Down Expand Up @@ -457,10 +462,7 @@ class FBXConverter {
NodeAnimBitMap node_anim_chain_bits;

// number of nodes with the same name
using NodeAnimNameMap = std::unordered_map<std::string, unsigned int>;
NodeAnimNameMap mNodeNameInstances;

using NodeNameCache = std::unordered_set<std::string>;
using NodeNameCache = std::unordered_map<std::string, unsigned int>;
NodeNameCache mNodeNames;

double anim_fps;
Expand Down
Loading

0 comments on commit 4feefaf

Please sign in to comment.