Merge branch 'master' into kimkulling-patch-8

pull/3516/head
Kim Kulling 2020-12-07 16:55:07 +01:00 committed by GitHub
commit 1f8c75c871
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 186 additions and 131 deletions

View File

@ -185,6 +185,17 @@ std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiN
return unique_name; return unique_name;
} }
/// 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
{
PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {}
PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {}
aiNode* operator->() { return mNode; }
std::unique_ptr<aiNode> mOwnership;
aiNode* mNode;
};
/// todo: pre-build node hierarchy /// todo: pre-build node hierarchy
/// todo: get bone from stack /// todo: get bone from stack
/// todo: make map of aiBone* to aiNode* /// todo: make map of aiBone* to aiNode*
@ -192,137 +203,129 @@ std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiN
void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) { void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) {
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(id, "Model"); const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(id, "Model");
std::vector<aiNode *> nodes; std::vector<PotentialNode> nodes;
nodes.reserve(conns.size()); nodes.reserve(conns.size());
std::vector<aiNode *> nodes_chain; std::vector<PotentialNode> nodes_chain;
std::vector<aiNode *> post_nodes_chain; std::vector<PotentialNode> post_nodes_chain;
try { for (const Connection *con : conns) {
for (const Connection *con : conns) { // ignore object-property links
// ignore object-property links if (con->PropertyName().length()) {
if (con->PropertyName().length()) { // really important we document why this is ignored.
// really important we document why this is ignored. FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored");
FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored"); continue; //?
continue; //? }
// convert connection source object into Object base class
const Object *const object = con->SourceObject();
if (nullptr == object) {
FBXImporter::LogError("failed to convert source object for Model link");
continue;
}
// FBX Model::Cube, Model::Bone001, etc elements
// This detects if we can cast the object into this model structure.
const Model *const model = dynamic_cast<const Model *>(object);
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
// is employed by fbx) means that we may need multiple aiNode's
// to represent a fbx node's transformation.
// generate node transforms - this includes pivot data
// if need_additional_node is true then you t
const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain);
// assert that for the current node we must have at least a single transform
ai_assert(nodes_chain.size());
if (need_additional_node) {
nodes_chain.emplace_back(PotentialNode(node_name));
} }
// convert connection source object into Object base class //setup metadata on newest node
const Object *const object = con->SourceObject(); SetupNodeMetadata(*model, *nodes_chain.back().mNode);
if (nullptr == object) {
FBXImporter::LogError("failed to convert source object for Model link");
continue;
}
// FBX Model::Cube, Model::Bone001, etc elements // link all nodes in a row
// This detects if we can cast the object into this model structure. aiNode *last_parent = parent;
const Model *const model = dynamic_cast<const Model *>(object); for (PotentialNode& child : nodes_chain) {
ai_assert(child.mNode);
if (nullptr != model) { if (last_parent != parent) {
nodes_chain.clear(); last_parent->mNumChildren = 1;
post_nodes_chain.clear(); last_parent->mChildren = new aiNode *[1];
last_parent->mChildren[0] = child.mOwnership.release();
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
// is employed by fbx) means that we may need multiple aiNode's
// to represent a fbx node's transformation.
// generate node transforms - this includes pivot data
// if need_additional_node is true then you t
const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain);
// assert that for the current node we must have at least a single transform
ai_assert(nodes_chain.size());
if (need_additional_node) {
nodes_chain.push_back(new aiNode(node_name));
} }
//setup metadata on newest node child->mParent = last_parent;
SetupNodeMetadata(*model, *nodes_chain.back()); last_parent = child.mNode;
// link all nodes in a row new_abs_transform *= child->mTransformation;
aiNode *last_parent = parent; }
for (aiNode *child : nodes_chain) {
ai_assert(child); // attach geometry
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");
// if so, link the geometric transform inverse nodes
// before we attach any child nodes
if (child_conns.size()) {
for (PotentialNode& postnode : post_nodes_chain) {
ai_assert(postnode.mNode);
if (last_parent != parent) { if (last_parent != parent) {
last_parent->mNumChildren = 1; last_parent->mNumChildren = 1;
last_parent->mChildren = new aiNode *[1]; last_parent->mChildren = new aiNode *[1];
last_parent->mChildren[0] = child; last_parent->mChildren[0] = postnode.mOwnership.release();
} }
child->mParent = last_parent; postnode->mParent = last_parent;
last_parent = child; last_parent = postnode.mNode;
new_abs_transform *= child->mTransformation; new_abs_transform *= postnode->mTransformation;
} }
} else {
// attach geometry // free the nodes we allocated as we don't need them
ConvertModel(*model, nodes_chain.back(), root_node, new_abs_transform); post_nodes_chain.clear();
// check if there will be any child nodes
const std::vector<const Connection *> &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model");
// if so, link the geometric transform inverse nodes
// before we attach any child nodes
if (child_conns.size()) {
for (aiNode *postnode : post_nodes_chain) {
ai_assert(postnode);
if (last_parent != parent) {
last_parent->mNumChildren = 1;
last_parent->mChildren = new aiNode *[1];
last_parent->mChildren[0] = postnode;
}
postnode->mParent = last_parent;
last_parent = postnode;
new_abs_transform *= postnode->mTransformation;
}
} else {
// free the nodes we allocated as we don't need them
Util::delete_fun<aiNode> deleter;
std::for_each(
post_nodes_chain.begin(),
post_nodes_chain.end(),
deleter);
}
// recursion call - child nodes
ConvertNodes(model->ID(), last_parent, root_node);
if (doc.Settings().readLights) {
ConvertLights(*model, node_name);
}
if (doc.Settings().readCameras) {
ConvertCameras(*model, node_name);
}
nodes.push_back(nodes_chain.front());
nodes_chain.clear();
} }
// recursion call - child nodes
ConvertNodes(model->ID(), last_parent, root_node);
if (doc.Settings().readLights) {
ConvertLights(*model, node_name);
}
if (doc.Settings().readCameras) {
ConvertCameras(*model, node_name);
}
nodes.push_back(std::move(nodes_chain.front()));
nodes_chain.clear();
} }
}
if (nodes.size()) { if (nodes.size()) {
parent->mChildren = new aiNode *[nodes.size()](); parent->mChildren = new aiNode *[nodes.size()]();
parent->mNumChildren = static_cast<unsigned int>(nodes.size()); parent->mNumChildren = static_cast<unsigned int>(nodes.size());
std::swap_ranges(nodes.begin(), nodes.end(), parent->mChildren); for (unsigned int i = 0; i < nodes.size(); ++i)
} else { {
parent->mNumChildren = 0; parent->mChildren[i] = nodes[i].mOwnership.release();
parent->mChildren = nullptr;
} }
nodes.clear();
} catch (std::exception &) { } else {
Util::delete_fun<aiNode> deleter; parent->mNumChildren = 0;
std::for_each(nodes.begin(), nodes.end(), deleter); parent->mChildren = nullptr;
std::for_each(nodes_chain.begin(), nodes_chain.end(), deleter);
std::for_each(post_nodes_chain.begin(), post_nodes_chain.end(), deleter);
} }
} }
@ -681,8 +684,8 @@ std::string FBXConverter::NameTransformationChainNode(const std::string &name, T
return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp); return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp);
} }
bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std::string &name, std::vector<aiNode *> &output_nodes, bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std::string &name, std::vector<PotentialNode> &output_nodes,
std::vector<aiNode *> &post_output_nodes) { std::vector<PotentialNode> &post_output_nodes) {
const PropertyTable &props = model.Props(); const PropertyTable &props = model.Props();
const Model::RotOrder rot = model.RotationOrder(); const Model::RotOrder rot = model.RotationOrder();
@ -828,7 +831,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
chain[i] = chain[i].Inverse(); chain[i] = chain[i].Inverse();
} }
aiNode *nd = new aiNode(); PotentialNode nd;
nd->mName.Set(NameTransformationChainNode(name, comp)); nd->mName.Set(NameTransformationChainNode(name, comp));
nd->mTransformation = chain[i]; nd->mTransformation = chain[i];
@ -836,9 +839,9 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
if (comp == TransformationComp_GeometricScalingInverse || if (comp == TransformationComp_GeometricScalingInverse ||
comp == TransformationComp_GeometricRotationInverse || comp == TransformationComp_GeometricRotationInverse ||
comp == TransformationComp_GeometricTranslationInverse) { comp == TransformationComp_GeometricTranslationInverse) {
post_output_nodes.push_back(nd); post_output_nodes.emplace_back(std::move(nd));
} else { } else {
output_nodes.push_back(nd); output_nodes.emplace_back(std::move(nd));
} }
} }
@ -847,8 +850,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
} }
// else, we can just multiply the matrices together // else, we can just multiply the matrices together
aiNode *nd = new aiNode(); PotentialNode nd;
output_nodes.push_back(nd);
// name passed to the method is already unique // name passed to the method is already unique
nd->mName.Set(name); nd->mName.Set(name);
@ -857,6 +859,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
for (unsigned int i = TransformationComp_Translation; i < TransformationComp_MAXIMUM; i++) { for (unsigned int i = TransformationComp_Translation; i < TransformationComp_MAXIMUM; i++) {
nd->mTransformation = nd->mTransformation * chain[i]; nd->mTransformation = nd->mTransformation * chain[i];
} }
output_nodes.push_back(std::move(nd));
return false; return false;
} }

View File

@ -171,9 +171,10 @@ private:
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
/** /**
* note: memory for output_nodes will be managed by the caller * note: memory for output_nodes is managed by the caller, via the PotentialNode struct.
*/ */
bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes); struct PotentialNode;
bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<PotentialNode>& output_nodes, std::vector<PotentialNode>& post_output_nodes);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void SetupNodeMetadata(const Model& model, aiNode& nd); void SetupNodeMetadata(const Model& model, aiNode& nd);

View File

@ -96,8 +96,9 @@ void ScenePreprocessor::ProcessMesh(aiMesh *mesh) {
if (!mesh->mTextureCoords[i]) { if (!mesh->mTextureCoords[i]) {
mesh->mNumUVComponents[i] = 0; mesh->mNumUVComponents[i] = 0;
} else { } else {
if (!mesh->mNumUVComponents[i]) if (!mesh->mNumUVComponents[i]) {
mesh->mNumUVComponents[i] = 2; mesh->mNumUVComponents[i] = 2;
}
aiVector3D *p = mesh->mTextureCoords[i], *end = p + mesh->mNumVertices; aiVector3D *p = mesh->mTextureCoords[i], *end = p + mesh->mNumVertices;
@ -105,16 +106,19 @@ void ScenePreprocessor::ProcessMesh(aiMesh *mesh) {
// as if they were 2D channels .. just in case an application doesn't handle // as if they were 2D channels .. just in case an application doesn't handle
// this case // this case
if (2 == mesh->mNumUVComponents[i]) { if (2 == mesh->mNumUVComponents[i]) {
for (; p != end; ++p) for (; p != end; ++p) {
p->z = 0.f; p->z = 0.f;
}
} else if (1 == mesh->mNumUVComponents[i]) { } else if (1 == mesh->mNumUVComponents[i]) {
for (; p != end; ++p) for (; p != end; ++p) {
p->z = p->y = 0.f; p->z = p->y = 0.f;
}
} else if (3 == mesh->mNumUVComponents[i]) { } else if (3 == mesh->mNumUVComponents[i]) {
// Really 3D coordinates? Check whether the third coordinate is != 0 for at least one element // Really 3D coordinates? Check whether the third coordinate is != 0 for at least one element
for (; p != end; ++p) { for (; p != end; ++p) {
if (p->z != 0) if (p->z != 0) {
break; break;
}
} }
if (p == end) { if (p == end) {
ASSIMP_LOG_WARN("ScenePreprocessor: UVs are declared to be 3D but they're obviously not. Reverting to 2D."); ASSIMP_LOG_WARN("ScenePreprocessor: UVs are declared to be 3D but they're obviously not. Reverting to 2D.");
@ -151,7 +155,6 @@ void ScenePreprocessor::ProcessMesh(aiMesh *mesh) {
// If tangents and normals are given but no bitangents compute them // If tangents and normals are given but no bitangents compute them
if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) { if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) {
mesh->mBitangents = new aiVector3D[mesh->mNumVertices]; mesh->mBitangents = new aiVector3D[mesh->mNumVertices];
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
mesh->mBitangents[i] = mesh->mNormals[i] ^ mesh->mTangents[i]; mesh->mBitangents[i] = mesh->mNormals[i] ^ mesh->mTangents[i];
@ -165,11 +168,9 @@ void ScenePreprocessor::ProcessAnimation(aiAnimation *anim) {
for (unsigned int i = 0; i < anim->mNumChannels; ++i) { for (unsigned int i = 0; i < anim->mNumChannels; ++i) {
aiNodeAnim *channel = anim->mChannels[i]; aiNodeAnim *channel = anim->mChannels[i];
/* If the exact duration of the animation is not given // If the exact duration of the animation is not given
* compute it now. // compute it now.
*/
if (anim->mDuration == -1.) { if (anim->mDuration == -1.) {
// Position keys // Position keys
for (unsigned int j = 0; j < channel->mNumPositionKeys; ++j) { for (unsigned int j = 0; j < channel->mNumPositionKeys; ++j) {
aiVectorKey &key = channel->mPositionKeys[j]; aiVectorKey &key = channel->mPositionKeys[j];
@ -192,11 +193,10 @@ void ScenePreprocessor::ProcessAnimation(aiAnimation *anim) {
} }
} }
/* Check whether the animation channel has no rotation // Check whether the animation channel has no rotation
* or position tracks. In this case we generate a dummy // or position tracks. In this case we generate a dummy
* track from the information we have in the transformation // track from the information we have in the transformation
* matrix of the corresponding node. // matrix of the corresponding node.
*/
if (!channel->mNumRotationKeys || !channel->mNumPositionKeys || !channel->mNumScalingKeys) { if (!channel->mNumRotationKeys || !channel->mNumPositionKeys || !channel->mNumScalingKeys) {
// Find the node that belongs to this animation // Find the node that belongs to this animation
aiNode *node = scene->mRootNode->FindNode(channel->mNodeName); aiNode *node = scene->mRootNode->FindNode(channel->mNodeName);
@ -210,6 +210,10 @@ void ScenePreprocessor::ProcessAnimation(aiAnimation *anim) {
// No rotation keys? Generate a dummy track // No rotation keys? Generate a dummy track
if (!channel->mNumRotationKeys) { if (!channel->mNumRotationKeys) {
if (channel->mRotationKeys) {
delete[] channel->mRotationKeys;
channel->mRotationKeys = nullptr;
}
ai_assert(!channel->mRotationKeys); ai_assert(!channel->mRotationKeys);
channel->mNumRotationKeys = 1; channel->mNumRotationKeys = 1;
channel->mRotationKeys = new aiQuatKey[1]; channel->mRotationKeys = new aiQuatKey[1];
@ -225,6 +229,10 @@ void ScenePreprocessor::ProcessAnimation(aiAnimation *anim) {
// No scaling keys? Generate a dummy track // No scaling keys? Generate a dummy track
if (!channel->mNumScalingKeys) { if (!channel->mNumScalingKeys) {
if (channel->mScalingKeys) {
delete[] channel->mScalingKeys;
channel->mScalingKeys = nullptr;
}
ai_assert(!channel->mScalingKeys); ai_assert(!channel->mScalingKeys);
channel->mNumScalingKeys = 1; channel->mNumScalingKeys = 1;
channel->mScalingKeys = new aiVectorKey[1]; channel->mScalingKeys = new aiVectorKey[1];
@ -240,6 +248,10 @@ void ScenePreprocessor::ProcessAnimation(aiAnimation *anim) {
// No position keys? Generate a dummy track // No position keys? Generate a dummy track
if (!channel->mNumPositionKeys) { if (!channel->mNumPositionKeys) {
if (channel->mPositionKeys) {
delete[] channel->mPositionKeys;
channel->mPositionKeys = nullptr;
}
ai_assert(!channel->mPositionKeys); ai_assert(!channel->mPositionKeys);
channel->mNumPositionKeys = 1; channel->mNumPositionKeys = 1;
channel->mPositionKeys = new aiVectorKey[1]; channel->mPositionKeys = new aiVectorKey[1];

View File

@ -408,6 +408,45 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
} }
} }
// ... and copy all the morph targets for all the vertices which made it into the new submesh
if (pMesh->mNumAnimMeshes > 0) {
newMesh->mNumAnimMeshes = pMesh->mNumAnimMeshes;
newMesh->mAnimMeshes = new aiAnimMesh*[newMesh->mNumAnimMeshes];
for (unsigned int morphIdx = 0; morphIdx < newMesh->mNumAnimMeshes; ++morphIdx) {
aiAnimMesh* origTarget = pMesh->mAnimMeshes[morphIdx];
aiAnimMesh* newTarget = new aiAnimMesh;
newTarget->mName = origTarget->mName;
newTarget->mWeight = origTarget->mWeight;
newTarget->mNumVertices = numSubMeshVertices;
newTarget->mVertices = new aiVector3D[numSubMeshVertices];
newMesh->mAnimMeshes[morphIdx] = newTarget;
if (origTarget->HasNormals()) {
newTarget->mNormals = new aiVector3D[numSubMeshVertices];
}
if (origTarget->HasTangentsAndBitangents()) {
newTarget->mTangents = new aiVector3D[numSubMeshVertices];
newTarget->mBitangents = new aiVector3D[numSubMeshVertices];
}
for( unsigned int vi = 0; vi < numSubMeshVertices; ++vi) {
// find the source vertex for it in the source mesh
unsigned int previousIndex = previousVertexIndices[vi];
newTarget->mVertices[vi] = origTarget->mVertices[previousIndex];
if (newTarget->HasNormals()) {
newTarget->mNormals[vi] = origTarget->mNormals[previousIndex];
}
if (newTarget->HasTangentsAndBitangents()) {
newTarget->mTangents[vi] = origTarget->mTangents[previousIndex];
newTarget->mBitangents[vi] = origTarget->mBitangents[previousIndex];
}
}
}
}
// I have the strange feeling that this will break apart at some point in time... // I have the strange feeling that this will break apart at some point in time...
} }
} }