- fbx: add option to detect dummy animation tracks and to remove them. Actually, this is mostly a debugging aid (and it cuts down memory usage).
parent
0d2cb96092
commit
54be52ea28
|
@ -282,6 +282,15 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
aiVector3D TransformationCompDefaultValue(TransformationComp comp)
|
||||||
|
{
|
||||||
|
// XXX a neat way to solve the never-ending special cases for scaling
|
||||||
|
// would be to do everything in log space!
|
||||||
|
return comp == TransformationComp_Scaling ? aiVector3D(1.f,1.f,1.f) : aiVector3D();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
enum RotationMode
|
enum RotationMode
|
||||||
{
|
{
|
||||||
RotationMode_Euler_XYZ
|
RotationMode_Euler_XYZ
|
||||||
|
@ -1316,10 +1325,6 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// name -> prefix_stripped?
|
|
||||||
typedef std::map<std::string, bool> NodeNameMap;
|
|
||||||
NodeNameMap node_names;
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
std::string FixNodeName(const std::string& name)
|
std::string FixNodeName(const std::string& name)
|
||||||
{
|
{
|
||||||
|
@ -1458,6 +1463,17 @@ private:
|
||||||
NodeMap node_property_map;
|
NodeMap node_property_map;
|
||||||
ai_assert(curves.size());
|
ai_assert(curves.size());
|
||||||
|
|
||||||
|
// sanity check whether the input is ok
|
||||||
|
#ifdef _DEBUG
|
||||||
|
{ const Object* target = NULL;
|
||||||
|
BOOST_FOREACH(const AnimationCurveNode* node, curves) {
|
||||||
|
if(!target) {
|
||||||
|
target = node->Target();
|
||||||
|
}
|
||||||
|
ai_assert(node->Target() == target);
|
||||||
|
}}
|
||||||
|
#endif
|
||||||
|
|
||||||
const AnimationCurveNode* curve_node;
|
const AnimationCurveNode* curve_node;
|
||||||
BOOST_FOREACH(const AnimationCurveNode* node, curves) {
|
BOOST_FOREACH(const AnimationCurveNode* node, curves) {
|
||||||
ai_assert(node);
|
ai_assert(node);
|
||||||
|
@ -1477,6 +1493,9 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
ai_assert(curve_node);
|
ai_assert(curve_node);
|
||||||
|
ai_assert(curve_node->TargetAsModel());
|
||||||
|
|
||||||
|
const Model& target = *curve_node->TargetAsModel();
|
||||||
|
|
||||||
// check for all possible transformation components
|
// check for all possible transformation components
|
||||||
NodeMap::const_iterator chain[TransformationComp_MAXIMUM];
|
NodeMap::const_iterator chain[TransformationComp_MAXIMUM];
|
||||||
|
@ -1495,6 +1514,14 @@ private:
|
||||||
|
|
||||||
chain[i] = node_property_map.find(NameTransformationCompProperty(comp));
|
chain[i] = node_property_map.find(NameTransformationCompProperty(comp));
|
||||||
if (chain[i] != node_property_map.end()) {
|
if (chain[i] != node_property_map.end()) {
|
||||||
|
|
||||||
|
// check if this curves contains redundant information by looking
|
||||||
|
// up the corresponding node's transformation chain.
|
||||||
|
if (doc.Settings().optimizeEmptyAnimationCurves && IsRedundantAnimationData(target, comp, (*chain[i]).second)) {
|
||||||
|
FBXImporter::LogDebug("dropping redundant animation channel for node " + target.Name());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
has_any = true;
|
has_any = true;
|
||||||
|
|
||||||
if (comp != TransformationComp_Rotation && comp != TransformationComp_Scaling &&
|
if (comp != TransformationComp_Rotation && comp != TransformationComp_Scaling &&
|
||||||
|
@ -1510,13 +1537,10 @@ private:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ai_assert(curve_node->TargetAsModel());
|
|
||||||
|
|
||||||
// this needs to play nicely with GenerateTransformationNodeChain() which will
|
// this needs to play nicely with GenerateTransformationNodeChain() which will
|
||||||
// be invoked _later_ (animations come first). If this node has only rotation,
|
// be invoked _later_ (animations come first). If this node has only rotation,
|
||||||
// scaling and translation _and_ there are no animated other components either,
|
// scaling and translation _and_ there are no animated other components either,
|
||||||
// we can use a single node and also a single node animation channel.
|
// we can use a single node and also a single node animation channel.
|
||||||
const Model& target = *curve_node->TargetAsModel();
|
|
||||||
if (!has_complex && !NeedsComplexTransformationChain(target)) {
|
if (!has_complex && !NeedsComplexTransformationChain(target)) {
|
||||||
|
|
||||||
aiNodeAnim* const nd = GenerateSimpleNodeAnim(fixed_name, target, chain,
|
aiNodeAnim* const nd = GenerateSimpleNodeAnim(fixed_name, target, chain,
|
||||||
|
@ -1635,6 +1659,53 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
bool IsRedundantAnimationData(const Model& target,
|
||||||
|
TransformationComp comp,
|
||||||
|
const std::vector<const AnimationCurveNode*>& curves)
|
||||||
|
{
|
||||||
|
ai_assert(curves.size());
|
||||||
|
|
||||||
|
// look for animation nodes with
|
||||||
|
// * sub channels for all relevant components set
|
||||||
|
// * one key/value pair per component
|
||||||
|
// * combined values match up the corresponding value in the bind pose node transformation
|
||||||
|
// only such nodes are 'redundant' for this function.
|
||||||
|
|
||||||
|
if (curves.size() > 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AnimationCurveNode& nd = *curves.front();
|
||||||
|
const AnimationCurveMap& sub_curves = nd.Curves();
|
||||||
|
|
||||||
|
const AnimationCurveMap::const_iterator dx = sub_curves.find("d|X");
|
||||||
|
const AnimationCurveMap::const_iterator dy = sub_curves.find("d|Y");
|
||||||
|
const AnimationCurveMap::const_iterator dz = sub_curves.find("d|Z");
|
||||||
|
|
||||||
|
if (dx == sub_curves.end() || dy == sub_curves.end() || dz == sub_curves.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const KeyValueList& vx = (*dx).second->GetValues();
|
||||||
|
const KeyValueList& vy = (*dy).second->GetValues();
|
||||||
|
const KeyValueList& vz = (*dz).second->GetValues();
|
||||||
|
|
||||||
|
if(vx.size() != 1 || vy.size() != 1 || vz.size() != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const aiVector3D dyn_val = aiVector3D(vx[0], vy[0], vz[0]);
|
||||||
|
const aiVector3D& static_val = PropertyGet<aiVector3D>(target.Props(),
|
||||||
|
NameTransformationCompProperty(comp),
|
||||||
|
TransformationCompDefaultValue(comp)
|
||||||
|
);
|
||||||
|
|
||||||
|
const float epsilon = 1e-6f;
|
||||||
|
return (dyn_val - static_val).SquareLength() < epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
aiNodeAnim* GenerateRotationNodeAnim(const std::string& name,
|
aiNodeAnim* GenerateRotationNodeAnim(const std::string& name,
|
||||||
const Model& target,
|
const Model& target,
|
||||||
|
@ -2101,13 +2172,17 @@ private:
|
||||||
typedef std::map<const Material*, unsigned int> MaterialMap;
|
typedef std::map<const Material*, unsigned int> MaterialMap;
|
||||||
MaterialMap materials_converted;
|
MaterialMap materials_converted;
|
||||||
|
|
||||||
|
|
||||||
typedef std::map<const Geometry*, std::vector<unsigned int> > MeshMap;
|
typedef std::map<const Geometry*, std::vector<unsigned int> > MeshMap;
|
||||||
MeshMap meshes_converted;
|
MeshMap meshes_converted;
|
||||||
|
|
||||||
|
// fixed node name -> which trafo chain components have animations?
|
||||||
typedef std::map<std::string, unsigned int> NodeAnimBitMap;
|
typedef std::map<std::string, unsigned int> NodeAnimBitMap;
|
||||||
NodeAnimBitMap node_anim_chain_bits;
|
NodeAnimBitMap node_anim_chain_bits;
|
||||||
|
|
||||||
|
// name -> has had its prefix_stripped?
|
||||||
|
typedef std::map<std::string, bool> NodeNameMap;
|
||||||
|
NodeNameMap node_names;
|
||||||
|
|
||||||
|
|
||||||
aiScene* const out;
|
aiScene* const out;
|
||||||
const FBX::Document& doc;
|
const FBX::Document& doc;
|
||||||
|
|
|
@ -60,6 +60,7 @@ struct ImportSettings
|
||||||
, strictMode(true)
|
, strictMode(true)
|
||||||
, readWeights(true)
|
, readWeights(true)
|
||||||
, preservePivots(true)
|
, preservePivots(true)
|
||||||
|
, optimizeEmptyAnimationCurves(true)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,6 +127,11 @@ struct ImportSettings
|
||||||
* Rotation
|
* Rotation
|
||||||
**/
|
**/
|
||||||
bool preservePivots;
|
bool preservePivots;
|
||||||
|
|
||||||
|
/** do not import animation curves that specify a constant
|
||||||
|
* values matching the corresponding node transformation.
|
||||||
|
* The default value is true. */
|
||||||
|
bool optimizeEmptyAnimationCurves;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue