Morph animation support for collada
parent
a97a4fb03b
commit
9621dff027
|
@ -173,6 +173,8 @@ SET( Common_SRCS
|
||||||
XMLTools.h
|
XMLTools.h
|
||||||
Version.cpp
|
Version.cpp
|
||||||
IOStreamBuffer.h
|
IOStreamBuffer.h
|
||||||
|
CreateAnimMesh.h
|
||||||
|
CreateAnimMesh.cpp
|
||||||
)
|
)
|
||||||
SOURCE_GROUP(Common FILES ${Common_SRCS})
|
SOURCE_GROUP(Common FILES ${Common_SRCS})
|
||||||
|
|
||||||
|
|
|
@ -89,6 +89,21 @@ enum InputType
|
||||||
IT_Bitangent
|
IT_Bitangent
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Supported controller types */
|
||||||
|
enum ControllerType
|
||||||
|
{
|
||||||
|
Skin,
|
||||||
|
Morph
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Supported morph methods */
|
||||||
|
enum MorphMethod
|
||||||
|
{
|
||||||
|
Normalized,
|
||||||
|
Relative
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Contains all data for one of the different transformation types */
|
/** Contains all data for one of the different transformation types */
|
||||||
struct Transform
|
struct Transform
|
||||||
{
|
{
|
||||||
|
@ -380,6 +395,12 @@ enum PrimitiveType
|
||||||
/** A skeleton controller to deform a mesh with the use of joints */
|
/** A skeleton controller to deform a mesh with the use of joints */
|
||||||
struct Controller
|
struct Controller
|
||||||
{
|
{
|
||||||
|
// controller type
|
||||||
|
ControllerType mType;
|
||||||
|
|
||||||
|
// Morphing method if type is Morph
|
||||||
|
MorphMethod mMethod;
|
||||||
|
|
||||||
// the URL of the mesh deformed by the controller.
|
// the URL of the mesh deformed by the controller.
|
||||||
std::string mMeshId;
|
std::string mMeshId;
|
||||||
|
|
||||||
|
@ -402,6 +423,9 @@ struct Controller
|
||||||
|
|
||||||
// JointIndex-WeightIndex pairs for all vertices
|
// JointIndex-WeightIndex pairs for all vertices
|
||||||
std::vector< std::pair<size_t, size_t> > mWeights;
|
std::vector< std::pair<size_t, size_t> > mWeights;
|
||||||
|
|
||||||
|
std::string mMorphTarget;
|
||||||
|
std::string mMorphWeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A collada material. Pretty much the only member is a reference to an effect. */
|
/** A collada material. Pretty much the only member is a reference to an effect. */
|
||||||
|
@ -577,6 +601,12 @@ struct AnimationChannel
|
||||||
std::string mSourceTimes;
|
std::string mSourceTimes;
|
||||||
/** Source URL of the value values. Collada calls them "output". */
|
/** Source URL of the value values. Collada calls them "output". */
|
||||||
std::string mSourceValues;
|
std::string mSourceValues;
|
||||||
|
/** Source URL of the IN_TANGENT semantic values. */
|
||||||
|
std::string mInTanValues;
|
||||||
|
/** Source URL of the OUT_TANGENT semantic values. */
|
||||||
|
std::string mOutTanValues;
|
||||||
|
/** Source URL of the INTERPOLATION semantic values. */
|
||||||
|
std::string mInterpolationValues;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** An animation. Container for 0-x animation channels or 0-x animations */
|
/** An animation. Container for 0-x animation channels or 0-x animations */
|
||||||
|
@ -645,6 +675,7 @@ struct Animation
|
||||||
struct ChannelEntry
|
struct ChannelEntry
|
||||||
{
|
{
|
||||||
const Collada::AnimationChannel* mChannel; ///> the source channel
|
const Collada::AnimationChannel* mChannel; ///> the source channel
|
||||||
|
std::string mTargetId;
|
||||||
std::string mTransformId; // the ID of the transformation step of the node which is influenced
|
std::string mTransformId; // the ID of the transformation step of the node which is influenced
|
||||||
size_t mTransformIndex; // Index into the node's transform chain to apply the channel to
|
size_t mTransformIndex; // Index into the node's transform chain to apply the channel to
|
||||||
size_t mSubElement; // starting index inside the transform data
|
size_t mSubElement; // starting index inside the transform data
|
||||||
|
|
|
@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "ParsingUtils.h"
|
#include "ParsingUtils.h"
|
||||||
#include "SkeletonMeshBuilder.h"
|
#include "SkeletonMeshBuilder.h"
|
||||||
#include "Defines.h"
|
#include "Defines.h"
|
||||||
|
#include "CreateAnimMesh.h"
|
||||||
|
|
||||||
#include "time.h"
|
#include "time.h"
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
@ -150,6 +151,7 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
|
||||||
mMeshIndexByID.clear();
|
mMeshIndexByID.clear();
|
||||||
mMaterialIndexByName.clear();
|
mMaterialIndexByName.clear();
|
||||||
mMeshes.clear();
|
mMeshes.clear();
|
||||||
|
mTargetMeshes.clear();
|
||||||
newMats.clear();
|
newMats.clear();
|
||||||
mLights.clear();
|
mLights.clear();
|
||||||
mCameras.clear();
|
mCameras.clear();
|
||||||
|
@ -571,6 +573,21 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Find mesh from either meshes or morph target meshes
|
||||||
|
aiMesh *ColladaLoader::findMesh(std::string meshid)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < mMeshes.size(); i++)
|
||||||
|
if (std::string(mMeshes[i]->mName.data) == meshid)
|
||||||
|
return mMeshes[i];
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < mTargetMeshes.size(); i++)
|
||||||
|
if (std::string(mTargetMeshes[i]->mName.data) == meshid)
|
||||||
|
return mTargetMeshes[i];
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh
|
// Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh
|
||||||
aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh,
|
aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh,
|
||||||
|
@ -656,8 +673,70 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
|
||||||
face.mIndices[b] = static_cast<unsigned int>(vertex++);
|
face.mIndices[b] = static_cast<unsigned int>(vertex++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create morph target meshes if any
|
||||||
|
std::vector<aiMesh*> targetMeshes;
|
||||||
|
std::vector<float> targetWeights;
|
||||||
|
Collada::MorphMethod method;
|
||||||
|
|
||||||
|
for(std::map<std::string, Collada::Controller>::const_iterator it = pParser.mControllerLibrary.begin();
|
||||||
|
it != pParser.mControllerLibrary.end(); it++)
|
||||||
|
{
|
||||||
|
const Collada::Controller &c = it->second;
|
||||||
|
const Collada::Mesh* baseMesh = pParser.ResolveLibraryReference( pParser.mMeshLibrary, c.mMeshId);
|
||||||
|
|
||||||
|
if (c.mType == Collada::Morph && baseMesh->mName == pSrcMesh->mName)
|
||||||
|
{
|
||||||
|
const Collada::Accessor& targetAccessor = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, c.mMorphTarget);
|
||||||
|
const Collada::Accessor& weightAccessor = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, c.mMorphWeight);
|
||||||
|
const Collada::Data& targetData = pParser.ResolveLibraryReference( pParser.mDataLibrary, targetAccessor.mSource);
|
||||||
|
const Collada::Data& weightData = pParser.ResolveLibraryReference( pParser.mDataLibrary, weightAccessor.mSource);
|
||||||
|
|
||||||
|
// take method
|
||||||
|
method = c.mMethod;
|
||||||
|
|
||||||
|
if (!targetData.mIsStringArray)
|
||||||
|
throw DeadlyImportError( "target data must contain id. ");
|
||||||
|
if (weightData.mIsStringArray)
|
||||||
|
throw DeadlyImportError( "target weight data must not be textual ");
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < targetData.mStrings.size(); ++i)
|
||||||
|
{
|
||||||
|
const Collada::Mesh* targetMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, targetData.mStrings.at(i));
|
||||||
|
|
||||||
|
aiMesh *aimesh = findMesh(targetMesh->mName);
|
||||||
|
if (!aimesh)
|
||||||
|
{
|
||||||
|
if (targetMesh->mSubMeshes.size() > 1)
|
||||||
|
throw DeadlyImportError( "Morhing target mesh must be a single");
|
||||||
|
aimesh = CreateMesh(pParser, targetMesh, targetMesh->mSubMeshes.at(0), NULL, 0, 0);
|
||||||
|
mTargetMeshes.push_back(aimesh);
|
||||||
|
}
|
||||||
|
targetMeshes.push_back(aimesh);
|
||||||
|
}
|
||||||
|
for (unsigned int i = 0; i < weightData.mValues.size(); ++i)
|
||||||
|
targetWeights.push_back(weightData.mValues.at(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (targetMeshes.size() > 0 && targetWeights.size() == targetMeshes.size())
|
||||||
|
{
|
||||||
|
std::vector<aiAnimMesh*> animMeshes;
|
||||||
|
for (unsigned int i = 0; i < targetMeshes.size(); i++)
|
||||||
|
{
|
||||||
|
aiAnimMesh *animMesh = aiCreateAnimMesh(targetMeshes.at(i));
|
||||||
|
animMesh->mWeight = targetWeights[i];
|
||||||
|
animMeshes.push_back(animMesh);
|
||||||
|
}
|
||||||
|
dstMesh->mMethod = (method == Collada::Relative)
|
||||||
|
? aiMorphingMethod_MORPH_RELATIVE
|
||||||
|
: aiMorphingMethod_MORPH_NORMALIZED;
|
||||||
|
dstMesh->mAnimMeshes = new aiAnimMesh*[animMeshes.size()];
|
||||||
|
dstMesh->mNumAnimMeshes = animMeshes.size();
|
||||||
|
for (unsigned int i = 0; i < animMeshes.size(); i++)
|
||||||
|
dstMesh->mAnimMeshes[i] = animMeshes.at(i);
|
||||||
|
}
|
||||||
|
|
||||||
// create bones if given
|
// create bones if given
|
||||||
if( pSrcController)
|
if( pSrcController && pSrcController->mType == Collada::Skin)
|
||||||
{
|
{
|
||||||
// refuse if the vertex count does not match
|
// refuse if the vertex count does not match
|
||||||
// if( pSrcController->mWeightCounts.size() != dstMesh->mNumVertices)
|
// if( pSrcController->mWeightCounts.size() != dstMesh->mNumVertices)
|
||||||
|
@ -956,6 +1035,68 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
|
||||||
CreateAnimation( pScene, pParser, pSrcAnim, animName);
|
CreateAnimation( pScene, pParser, pSrcAnim, animName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MorphTimeValues
|
||||||
|
{
|
||||||
|
float mTime;
|
||||||
|
struct key
|
||||||
|
{
|
||||||
|
float mWeight;
|
||||||
|
unsigned int mValue;
|
||||||
|
};
|
||||||
|
std::vector<key> mKeys;
|
||||||
|
};
|
||||||
|
|
||||||
|
void insertMorphTimeValue(std::vector<MorphTimeValues> &values, float time, float weight, unsigned int value)
|
||||||
|
{
|
||||||
|
MorphTimeValues::key k;
|
||||||
|
k.mValue = value;
|
||||||
|
k.mWeight = weight;
|
||||||
|
if (values.size() == 0 || time < values[0].mTime)
|
||||||
|
{
|
||||||
|
MorphTimeValues val;
|
||||||
|
val.mTime = time;
|
||||||
|
val.mKeys.push_back(k);
|
||||||
|
values.insert(values.begin(), val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (time > values.back().mTime)
|
||||||
|
{
|
||||||
|
MorphTimeValues val;
|
||||||
|
val.mTime = time;
|
||||||
|
val.mKeys.push_back(k);
|
||||||
|
values.insert(values.end(), val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (unsigned int i = 0; i < values.size(); i++)
|
||||||
|
{
|
||||||
|
if (std::abs(time - values[i].mTime) < 1e-6f)
|
||||||
|
{
|
||||||
|
values[i].mKeys.push_back(k);
|
||||||
|
return;
|
||||||
|
} else if (time > values[i].mTime && time < values[i+1].mTime)
|
||||||
|
{
|
||||||
|
MorphTimeValues val;
|
||||||
|
val.mTime = time;
|
||||||
|
val.mKeys.push_back(k);
|
||||||
|
values.insert(values.begin() + i, val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// should not get here
|
||||||
|
}
|
||||||
|
|
||||||
|
float getWeightAtKey(const std::vector<MorphTimeValues> &values, int key, unsigned int value)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < values[key].mKeys.size(); i++)
|
||||||
|
{
|
||||||
|
if (values[key].mKeys[i].mValue == value)
|
||||||
|
return values[key].mKeys[i].mWeight;
|
||||||
|
}
|
||||||
|
// no value at key found, try to interpolate if present at other keys. if not, return zero
|
||||||
|
// TODO: interpolation
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructs the animation for the given source anim
|
// Constructs the animation for the given source anim
|
||||||
void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pName)
|
void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pName)
|
||||||
|
@ -965,6 +1106,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
|
||||||
CollectNodes( pScene->mRootNode, nodes);
|
CollectNodes( pScene->mRootNode, nodes);
|
||||||
|
|
||||||
std::vector<aiNodeAnim*> anims;
|
std::vector<aiNodeAnim*> anims;
|
||||||
|
std::vector<aiMeshMorphAnim*> morphAnims;
|
||||||
|
|
||||||
for( std::vector<const aiNode*>::const_iterator nit = nodes.begin(); nit != nodes.end(); ++nit)
|
for( std::vector<const aiNode*>::const_iterator nit = nodes.begin(); nit != nodes.end(); ++nit)
|
||||||
{
|
{
|
||||||
// find all the collada anim channels which refer to the current node
|
// find all the collada anim channels which refer to the current node
|
||||||
|
@ -988,7 +1131,20 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
|
||||||
// find the slash that separates the node name - there should be only one
|
// find the slash that separates the node name - there should be only one
|
||||||
std::string::size_type slashPos = srcChannel.mTarget.find( '/');
|
std::string::size_type slashPos = srcChannel.mTarget.find( '/');
|
||||||
if( slashPos == std::string::npos)
|
if( slashPos == std::string::npos)
|
||||||
|
{
|
||||||
|
std::string::size_type targetPos = srcChannel.mTarget.find(srcNode->mID);
|
||||||
|
if (targetPos == std::string::npos)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// not node transform, but something else. store as unknown animation channel for now
|
||||||
|
entry.mChannel = &(*cit);
|
||||||
|
entry.mTargetId = srcChannel.mTarget.substr(targetPos + pSrcAnim->mName.length(),
|
||||||
|
srcChannel.mTarget.length() - targetPos - pSrcAnim->mName.length());
|
||||||
|
if (entry.mTargetId.front() == '-')
|
||||||
|
entry.mTargetId = entry.mTargetId.substr(1);
|
||||||
|
entries.push_back(entry);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
if( srcChannel.mTarget.find( '/', slashPos+1) != std::string::npos)
|
if( srcChannel.mTarget.find( '/', slashPos+1) != std::string::npos)
|
||||||
continue;
|
continue;
|
||||||
std::string targetID = srcChannel.mTarget.substr( 0, slashPos);
|
std::string targetID = srcChannel.mTarget.substr( 0, slashPos);
|
||||||
|
@ -1068,8 +1224,14 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
|
||||||
if( srcNode->mTransforms[a].mID == entry.mTransformId)
|
if( srcNode->mTransforms[a].mID == entry.mTransformId)
|
||||||
entry.mTransformIndex = a;
|
entry.mTransformIndex = a;
|
||||||
|
|
||||||
if( entry.mTransformIndex == SIZE_MAX) {
|
if( entry.mTransformIndex == SIZE_MAX)
|
||||||
continue;
|
{
|
||||||
|
if (entry.mTransformId.find("morph-weights") != std::string::npos)
|
||||||
|
{
|
||||||
|
entry.mTargetId = entry.mTransformId;
|
||||||
|
entry.mTransformId = "";
|
||||||
|
} else
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry.mChannel = &(*cit);
|
entry.mChannel = &(*cit);
|
||||||
|
@ -1213,49 +1375,125 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
|
||||||
// ai_assert( resultTrafos.size() > 0);
|
// ai_assert( resultTrafos.size() > 0);
|
||||||
|
|
||||||
// build an animation channel for the given node out of these trafo keys
|
// build an animation channel for the given node out of these trafo keys
|
||||||
if( !resultTrafos.empty() )
|
if( !resultTrafos.empty() )
|
||||||
{
|
{
|
||||||
aiNodeAnim* dstAnim = new aiNodeAnim;
|
aiNodeAnim* dstAnim = new aiNodeAnim;
|
||||||
dstAnim->mNodeName = nodeName;
|
dstAnim->mNodeName = nodeName;
|
||||||
dstAnim->mNumPositionKeys = static_cast<unsigned int>(resultTrafos.size());
|
dstAnim->mNumPositionKeys = resultTrafos.size();
|
||||||
dstAnim->mNumRotationKeys= static_cast<unsigned int>(resultTrafos.size());
|
dstAnim->mNumRotationKeys= resultTrafos.size();
|
||||||
dstAnim->mNumScalingKeys = static_cast<unsigned int>(resultTrafos.size());
|
dstAnim->mNumScalingKeys = resultTrafos.size();
|
||||||
dstAnim->mPositionKeys = new aiVectorKey[resultTrafos.size()];
|
dstAnim->mPositionKeys = new aiVectorKey[resultTrafos.size()];
|
||||||
dstAnim->mRotationKeys = new aiQuatKey[resultTrafos.size()];
|
dstAnim->mRotationKeys = new aiQuatKey[resultTrafos.size()];
|
||||||
dstAnim->mScalingKeys = new aiVectorKey[resultTrafos.size()];
|
dstAnim->mScalingKeys = new aiVectorKey[resultTrafos.size()];
|
||||||
|
|
||||||
for( size_t a = 0; a < resultTrafos.size(); ++a)
|
for( size_t a = 0; a < resultTrafos.size(); ++a)
|
||||||
{
|
{
|
||||||
aiMatrix4x4 mat = resultTrafos[a];
|
aiMatrix4x4 mat = resultTrafos[a];
|
||||||
double time = double( mat.d4); // remember? time is stored in mat.d4
|
double time = double( mat.d4); // remember? time is stored in mat.d4
|
||||||
mat.d4 = 1.0f;
|
mat.d4 = 1.0f;
|
||||||
|
|
||||||
dstAnim->mPositionKeys[a].mTime = time;
|
dstAnim->mPositionKeys[a].mTime = time;
|
||||||
dstAnim->mRotationKeys[a].mTime = time;
|
dstAnim->mRotationKeys[a].mTime = time;
|
||||||
dstAnim->mScalingKeys[a].mTime = time;
|
dstAnim->mScalingKeys[a].mTime = time;
|
||||||
mat.Decompose( dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue);
|
mat.Decompose( dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
anims.push_back( dstAnim);
|
anims.push_back( dstAnim);
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
DefaultLogger::get()->warn( "Collada loader: found empty animation channel, ignored. Please check your exporter.");
|
DefaultLogger::get()->warn( "Collada loader: found empty animation channel, ignored. Please check your exporter.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !entries.empty() && entries.front().mTimeAccessor->mCount > 0 )
|
||||||
|
{
|
||||||
|
std::vector<Collada::ChannelEntry> morphChannels;
|
||||||
|
for( std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it)
|
||||||
|
{
|
||||||
|
Collada::ChannelEntry& e = *it;
|
||||||
|
|
||||||
|
// skip non-transform types
|
||||||
|
if (e.mTargetId.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (e.mTargetId.find("morph-weights") != std::string::npos)
|
||||||
|
morphChannels.push_back(e);
|
||||||
|
}
|
||||||
|
if (morphChannels.size() > 0)
|
||||||
|
{
|
||||||
|
// either 1) morph weight animation count should contain morph target count channels
|
||||||
|
// or 2) one channel with morph target count arrays
|
||||||
|
// assume first
|
||||||
|
|
||||||
|
aiMeshMorphAnim *morphAnim = new aiMeshMorphAnim;
|
||||||
|
morphAnim->mName.Set(nodeName);
|
||||||
|
|
||||||
|
std::vector<MorphTimeValues> morphTimeValues;
|
||||||
|
|
||||||
|
int morphAnimChannelIndex = 0;
|
||||||
|
for( std::vector<Collada::ChannelEntry>::iterator it = morphChannels.begin(); it != morphChannels.end(); ++it)
|
||||||
|
{
|
||||||
|
Collada::ChannelEntry& e = *it;
|
||||||
|
std::string::size_type apos = e.mTargetId.find('(');
|
||||||
|
std::string::size_type bpos = e.mTargetId.find(')');
|
||||||
|
if (apos == std::string::npos || bpos == std::string::npos)
|
||||||
|
// unknown way to specify weight -> ignore this animation
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// weight target can be in format Weight_M_N, Weight_N, WeightN, or some other way
|
||||||
|
// we ignore the name and just assume the channels are in the right order
|
||||||
|
for (unsigned int i = 0; i < e.mTimeData->mValues.size(); i++)
|
||||||
|
insertMorphTimeValue(morphTimeValues, e.mTimeData->mValues.at(i), e.mValueData->mValues.at(i), morphAnimChannelIndex);
|
||||||
|
|
||||||
|
++morphAnimChannelIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
morphAnim->mNumKeys = morphTimeValues.size();
|
||||||
|
morphAnim->mKeys = new aiMeshMorphKey[morphAnim->mNumKeys];
|
||||||
|
for (unsigned int key = 0; key < morphAnim->mNumKeys; key++)
|
||||||
|
{
|
||||||
|
morphAnim->mKeys[key].mNumValuesAndWeights = morphChannels.size();
|
||||||
|
morphAnim->mKeys[key].mValues = new unsigned int [morphChannels.size()];
|
||||||
|
morphAnim->mKeys[key].mWeights = new double [morphChannels.size()];
|
||||||
|
|
||||||
|
morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime;
|
||||||
|
for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); valueIndex++)
|
||||||
|
{
|
||||||
|
morphAnim->mKeys[key].mValues[valueIndex] = valueIndex;
|
||||||
|
morphAnim->mKeys[key].mWeights[valueIndex] = getWeightAtKey(morphTimeValues, key, valueIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
morphAnims.push_back(morphAnim);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !anims.empty())
|
if( !anims.empty() || !morphAnims.empty())
|
||||||
{
|
{
|
||||||
aiAnimation* anim = new aiAnimation;
|
aiAnimation* anim = new aiAnimation;
|
||||||
anim->mName.Set( pName);
|
anim->mName.Set( pName);
|
||||||
anim->mNumChannels = static_cast<unsigned int>(anims.size());
|
anim->mNumChannels = anims.size();
|
||||||
anim->mChannels = new aiNodeAnim*[anims.size()];
|
if (anim->mNumChannels > 0)
|
||||||
std::copy( anims.begin(), anims.end(), anim->mChannels);
|
{
|
||||||
|
anim->mChannels = new aiNodeAnim*[anims.size()];
|
||||||
|
std::copy( anims.begin(), anims.end(), anim->mChannels);
|
||||||
|
}
|
||||||
|
anim->mNumMorphMeshChannels = morphAnims.size();
|
||||||
|
if (anim->mNumMorphMeshChannels > 0)
|
||||||
|
{
|
||||||
|
anim->mMorphMeshChannels = new aiMeshMorphAnim*[anim->mNumMorphMeshChannels];
|
||||||
|
std::copy( morphAnims.begin(), morphAnims.end(), anim->mMorphMeshChannels);
|
||||||
|
}
|
||||||
anim->mDuration = 0.0f;
|
anim->mDuration = 0.0f;
|
||||||
for( size_t a = 0; a < anims.size(); ++a)
|
for( size_t a = 0; a < anims.size(); ++a)
|
||||||
{
|
{
|
||||||
anim->mDuration = std::max( anim->mDuration, anims[a]->mPositionKeys[anims[a]->mNumPositionKeys-1].mTime);
|
anim->mDuration = std::max( anim->mDuration, anims[a]->mPositionKeys[anims[a]->mNumPositionKeys-1].mTime);
|
||||||
anim->mDuration = std::max( anim->mDuration, anims[a]->mRotationKeys[anims[a]->mNumRotationKeys-1].mTime);
|
anim->mDuration = std::max( anim->mDuration, anims[a]->mRotationKeys[anims[a]->mNumRotationKeys-1].mTime);
|
||||||
anim->mDuration = std::max( anim->mDuration, anims[a]->mScalingKeys[anims[a]->mNumScalingKeys-1].mTime);
|
anim->mDuration = std::max( anim->mDuration, anims[a]->mScalingKeys[anims[a]->mNumScalingKeys-1].mTime);
|
||||||
|
}
|
||||||
|
for (size_t a = 0; a < morphAnims.size(); ++a)
|
||||||
|
{
|
||||||
|
anim->mDuration = std::max(anim->mDuration, morphAnims[a]->mKeys[morphAnims[a]->mNumKeys-1].mTime);
|
||||||
}
|
}
|
||||||
anim->mTicksPerSecond = 1;
|
anim->mTicksPerSecond = 1;
|
||||||
mAnims.push_back( anim);
|
mAnims.push_back( anim);
|
||||||
|
|
|
@ -118,6 +118,8 @@ protected:
|
||||||
void BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode,
|
void BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode,
|
||||||
aiNode* pTarget);
|
aiNode* pTarget);
|
||||||
|
|
||||||
|
aiMesh *findMesh(std::string meshid);
|
||||||
|
|
||||||
/** Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh */
|
/** Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh */
|
||||||
aiMesh* CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh,
|
aiMesh* CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh,
|
||||||
const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace);
|
const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace);
|
||||||
|
@ -224,6 +226,9 @@ protected:
|
||||||
/** Accumulated meshes for the target scene */
|
/** Accumulated meshes for the target scene */
|
||||||
std::vector<aiMesh*> mMeshes;
|
std::vector<aiMesh*> mMeshes;
|
||||||
|
|
||||||
|
/** Accumulated morph target meshes */
|
||||||
|
std::vector<aiMesh*> mTargetMeshes;
|
||||||
|
|
||||||
/** Temporary material list */
|
/** Temporary material list */
|
||||||
std::vector<std::pair<Collada::Effect*, aiMaterial*> > newMats;
|
std::vector<std::pair<Collada::Effect*, aiMaterial*> > newMats;
|
||||||
|
|
||||||
|
|
|
@ -585,6 +585,12 @@ void ColladaParser::ReadAnimationSampler( Collada::AnimationChannel& pChannel)
|
||||||
pChannel.mSourceTimes = source;
|
pChannel.mSourceTimes = source;
|
||||||
else if( strcmp( semantic, "OUTPUT") == 0)
|
else if( strcmp( semantic, "OUTPUT") == 0)
|
||||||
pChannel.mSourceValues = source;
|
pChannel.mSourceValues = source;
|
||||||
|
else if( strcmp( semantic, "IN_TANGENT") == 0)
|
||||||
|
pChannel.mInTanValues = source;
|
||||||
|
else if( strcmp( semantic, "OUT_TANGENT") == 0)
|
||||||
|
pChannel.mOutTanValues = source;
|
||||||
|
else if( strcmp( semantic, "INTERPOLATION") == 0)
|
||||||
|
pChannel.mInterpolationValues = source;
|
||||||
|
|
||||||
if( !mReader->isEmptyElement())
|
if( !mReader->isEmptyElement())
|
||||||
SkipElement();
|
SkipElement();
|
||||||
|
@ -647,6 +653,9 @@ void ColladaParser::ReadControllerLibrary()
|
||||||
// Reads a controller into the given mesh structure
|
// Reads a controller into the given mesh structure
|
||||||
void ColladaParser::ReadController( Collada::Controller& pController)
|
void ColladaParser::ReadController( Collada::Controller& pController)
|
||||||
{
|
{
|
||||||
|
// initial values
|
||||||
|
pController.mType = Skin;
|
||||||
|
pController.mMethod = Normalized;
|
||||||
while( mReader->read())
|
while( mReader->read())
|
||||||
{
|
{
|
||||||
if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
||||||
|
@ -654,8 +663,15 @@ void ColladaParser::ReadController( Collada::Controller& pController)
|
||||||
// two types of controllers: "skin" and "morph". Only the first one is relevant, we skip the other
|
// two types of controllers: "skin" and "morph". Only the first one is relevant, we skip the other
|
||||||
if( IsElement( "morph"))
|
if( IsElement( "morph"))
|
||||||
{
|
{
|
||||||
// should skip everything inside, so there's no danger of catching elements in between
|
pController.mType = Morph;
|
||||||
SkipElement();
|
int baseIndex = GetAttribute("source");
|
||||||
|
pController.mMeshId = mReader->getAttributeValue(baseIndex) + 1;
|
||||||
|
int methodIndex = GetAttribute("method");
|
||||||
|
if (methodIndex > 0) {
|
||||||
|
const char *method = mReader->getAttributeValue(methodIndex);
|
||||||
|
if (strcmp(method, "RELATIVE") == 0)
|
||||||
|
pController.mMethod = Relative;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if( IsElement( "skin"))
|
else if( IsElement( "skin"))
|
||||||
{
|
{
|
||||||
|
@ -693,6 +709,32 @@ void ColladaParser::ReadController( Collada::Controller& pController)
|
||||||
{
|
{
|
||||||
ReadControllerWeights( pController);
|
ReadControllerWeights( pController);
|
||||||
}
|
}
|
||||||
|
else if ( IsElement( "targets" ))
|
||||||
|
{
|
||||||
|
while (mReader->read()) {
|
||||||
|
if( mReader->getNodeType() == irr::io::EXN_ELEMENT) {
|
||||||
|
if ( IsElement( "input")) {
|
||||||
|
int semanticsIndex = GetAttribute("semantic");
|
||||||
|
int sourceIndex = GetAttribute("source");
|
||||||
|
|
||||||
|
const char *semantics = mReader->getAttributeValue(semanticsIndex);
|
||||||
|
const char *source = mReader->getAttributeValue(sourceIndex);
|
||||||
|
if (strcmp(semantics, "MORPH_TARGET") == 0) {
|
||||||
|
pController.mMorphTarget = source + 1;
|
||||||
|
}
|
||||||
|
else if (strcmp(semantics, "MORPH_WEIGHT") == 0)
|
||||||
|
{
|
||||||
|
pController.mMorphWeight = source + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
|
||||||
|
if( strcmp( mReader->getNodeName(), "targets") == 0)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
ThrowException( "Expected end of <targets> element.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// ignore the rest
|
// ignore the rest
|
||||||
|
@ -703,7 +745,7 @@ void ColladaParser::ReadController( Collada::Controller& pController)
|
||||||
{
|
{
|
||||||
if( strcmp( mReader->getNodeName(), "controller") == 0)
|
if( strcmp( mReader->getNodeName(), "controller") == 0)
|
||||||
break;
|
break;
|
||||||
else if( strcmp( mReader->getNodeName(), "skin") != 0)
|
else if( strcmp( mReader->getNodeName(), "skin") != 0 && strcmp( mReader->getNodeName(), "morph") != 0)
|
||||||
ThrowException( "Expected end of <controller> element.");
|
ThrowException( "Expected end of <controller> element.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
Copyright (c) 2006-2012, assimp team
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the following
|
||||||
|
conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CreateAnimMesh.h"
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh)
|
||||||
|
{
|
||||||
|
aiAnimMesh *animesh = new aiAnimMesh;
|
||||||
|
animesh->mVertices = NULL;
|
||||||
|
animesh->mNormals = NULL;
|
||||||
|
animesh->mTangents = NULL;
|
||||||
|
animesh->mBitangents = NULL;
|
||||||
|
animesh->mNumVertices = mesh->mNumVertices;
|
||||||
|
if (mesh->mVertices) {
|
||||||
|
animesh->mVertices = new aiVector3D[animesh->mNumVertices];
|
||||||
|
std::memcpy(animesh->mVertices, mesh->mVertices, mesh->mNumVertices * sizeof(aiVector3D));
|
||||||
|
}
|
||||||
|
if (mesh->mNormals) {
|
||||||
|
animesh->mNormals = new aiVector3D[animesh->mNumVertices];
|
||||||
|
std::memcpy(animesh->mNormals, mesh->mNormals, mesh->mNumVertices * sizeof(aiVector3D));
|
||||||
|
}
|
||||||
|
if (mesh->mTangents) {
|
||||||
|
animesh->mTangents = new aiVector3D[animesh->mNumVertices];
|
||||||
|
std::memcpy(animesh->mTangents, mesh->mTangents, mesh->mNumVertices * sizeof(aiVector3D));
|
||||||
|
}
|
||||||
|
if (mesh->mBitangents) {
|
||||||
|
animesh->mBitangents = new aiVector3D[animesh->mNumVertices];
|
||||||
|
std::memcpy(animesh->mBitangents, mesh->mBitangents, mesh->mNumVertices * sizeof(aiVector3D));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
|
||||||
|
if (mesh->mColors[i]) {
|
||||||
|
animesh->mColors[i] = new aiColor4D[animesh->mNumVertices];
|
||||||
|
std::memcpy(animesh->mColors[i], mesh->mColors[i], mesh->mNumVertices * sizeof(aiColor4D));
|
||||||
|
} else {
|
||||||
|
animesh->mColors[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||||
|
if (mesh->mTextureCoords[i]) {
|
||||||
|
animesh->mTextureCoords[i] = new aiVector3D[animesh->mNumVertices];
|
||||||
|
std::memcpy(animesh->mTextureCoords[i], mesh->mTextureCoords[i], mesh->mNumVertices * sizeof(aiVector3D));
|
||||||
|
} else {
|
||||||
|
animesh->mTextureCoords[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return animesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Assimp
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2016, assimp team
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file CreateAnimMesh.h
|
||||||
|
* Create AnimMesh from Mesh
|
||||||
|
*/
|
||||||
|
#ifndef INCLUDED_AI_CREATE_ANIM_MESH_H
|
||||||
|
#define INCLUDED_AI_CREATE_ANIM_MESH_H
|
||||||
|
|
||||||
|
#include <assimp/mesh.h>
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
/** Create aiAnimMesh from aiMesh. */
|
||||||
|
aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh);
|
||||||
|
|
||||||
|
} // end of namespace Assimp
|
||||||
|
#endif // INCLUDED_AI_CREATE_ANIM_MESH_H
|
||||||
|
|
|
@ -190,6 +190,39 @@ struct aiMeshKey
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** Binds a morph anim mesh to a specific point in time. */
|
||||||
|
struct aiMeshMorphKey
|
||||||
|
{
|
||||||
|
/** The time of this key */
|
||||||
|
double mTime;
|
||||||
|
|
||||||
|
/** The values and weights at the time of this key */
|
||||||
|
unsigned int *mValues;
|
||||||
|
double *mWeights;
|
||||||
|
|
||||||
|
/** The number of values and weights */
|
||||||
|
unsigned int mNumValuesAndWeights;
|
||||||
|
#ifdef __cplusplus
|
||||||
|
aiMeshMorphKey()
|
||||||
|
: mTime(0.0)
|
||||||
|
, mValues(NULL)
|
||||||
|
, mWeights(NULL)
|
||||||
|
, mNumValuesAndWeights(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
~aiMeshMorphKey()
|
||||||
|
{
|
||||||
|
if (mNumValuesAndWeights && mValues && mWeights) {
|
||||||
|
delete [] mValues;
|
||||||
|
delete [] mWeights;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Defines how an animation channel behaves outside the defined time
|
/** Defines how an animation channel behaves outside the defined time
|
||||||
* range. This corresponds to aiNodeAnim::mPreState and
|
* range. This corresponds to aiNodeAnim::mPreState and
|
||||||
|
@ -340,6 +373,37 @@ struct aiMeshAnim
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** Describes a morphing animation of a given mesh. */
|
||||||
|
struct aiMeshMorphAnim
|
||||||
|
{
|
||||||
|
/** Name of the mesh to be animated. An empty string is not allowed,
|
||||||
|
* animated meshes need to be named (not necessarily uniquely,
|
||||||
|
* the name can basically serve as wildcard to select a group
|
||||||
|
* of meshes with similar animation setup)*/
|
||||||
|
C_STRUCT aiString mName;
|
||||||
|
|
||||||
|
/** Size of the #mKeys array. Must be 1, at least. */
|
||||||
|
unsigned int mNumKeys;
|
||||||
|
|
||||||
|
/** Key frames of the animation. May not be NULL. */
|
||||||
|
C_STRUCT aiMeshMorphKey* mKeys;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
aiMeshMorphAnim()
|
||||||
|
: mNumKeys()
|
||||||
|
, mKeys()
|
||||||
|
{}
|
||||||
|
|
||||||
|
~aiMeshMorphAnim()
|
||||||
|
{
|
||||||
|
delete[] mKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** An animation consists of key-frame data for a number of nodes. For
|
/** An animation consists of key-frame data for a number of nodes. For
|
||||||
* each node affected by the animation a separate series of data is given.*/
|
* each node affected by the animation a separate series of data is given.*/
|
||||||
|
@ -372,6 +436,14 @@ struct aiAnimation {
|
||||||
* The array is mNumMeshChannels in size. */
|
* The array is mNumMeshChannels in size. */
|
||||||
C_STRUCT aiMeshAnim** mMeshChannels;
|
C_STRUCT aiMeshAnim** mMeshChannels;
|
||||||
|
|
||||||
|
/** The number of mesh animation channels. Each channel affects
|
||||||
|
* a single mesh and defines morphing animation. */
|
||||||
|
unsigned int mNumMorphMeshChannels;
|
||||||
|
|
||||||
|
/** The morph mesh animation channels. Each channel affects a single mesh.
|
||||||
|
* The array is mNumMorphMeshChannels in size. */
|
||||||
|
C_STRUCT aiMeshMorphAnim **mMorphMeshChannels;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
aiAnimation()
|
aiAnimation()
|
||||||
: mDuration(-1.)
|
: mDuration(-1.)
|
||||||
|
@ -379,7 +451,9 @@ struct aiAnimation {
|
||||||
, mNumChannels(0)
|
, mNumChannels(0)
|
||||||
, mChannels(NULL)
|
, mChannels(NULL)
|
||||||
, mNumMeshChannels(0)
|
, mNumMeshChannels(0)
|
||||||
, mMeshChannels(NULL) {
|
, mMeshChannels(NULL)
|
||||||
|
, mNumMorphMeshChannels(0)
|
||||||
|
, mMorphMeshChannels(NULL) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,6 +473,11 @@ struct aiAnimation {
|
||||||
|
|
||||||
delete [] mMeshChannels;
|
delete [] mMeshChannels;
|
||||||
}
|
}
|
||||||
|
if (mNumMorphMeshChannels && mMorphMeshChannels) {
|
||||||
|
for( unsigned int a = 0; a < mNumMorphMeshChannels; a++) {
|
||||||
|
delete mMorphMeshChannels[a];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
};
|
};
|
||||||
|
|
|
@ -378,6 +378,9 @@ struct aiAnimMesh
|
||||||
*/
|
*/
|
||||||
unsigned int mNumVertices;
|
unsigned int mNumVertices;
|
||||||
|
|
||||||
|
/** Weight of the AnimMesh. */
|
||||||
|
float mWeight;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
aiAnimMesh()
|
aiAnimMesh()
|
||||||
|
@ -446,6 +449,27 @@ struct aiAnimMesh
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** @brief Enumerates the methods of mesh morphing supported by Assimp.
|
||||||
|
*/
|
||||||
|
enum aiMorphingMethod
|
||||||
|
{
|
||||||
|
/** Interpolation between morph targets */
|
||||||
|
aiMorphingMethod_VERTEX_BLEND = 0x1,
|
||||||
|
|
||||||
|
/** Normalized morphing between morph targets */
|
||||||
|
aiMorphingMethod_MORPH_NORMALIZED = 0x2,
|
||||||
|
|
||||||
|
/** Relative morphing between morph targets */
|
||||||
|
aiMorphingMethod_MORPH_RELATIVE = 0x3,
|
||||||
|
|
||||||
|
/** This value is not used. It is just here to force the
|
||||||
|
* compiler to map this enum to a 32 Bit integer.
|
||||||
|
*/
|
||||||
|
#ifndef SWIG
|
||||||
|
_aiMorphingMethod_Force32Bit = INT_MAX
|
||||||
|
#endif
|
||||||
|
}; //! enum aiMorphingMethod
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** @brief A mesh represents a geometry or model with a single material.
|
/** @brief A mesh represents a geometry or model with a single material.
|
||||||
|
@ -600,14 +624,17 @@ struct aiMesh
|
||||||
C_STRUCT aiString mName;
|
C_STRUCT aiString mName;
|
||||||
|
|
||||||
|
|
||||||
/** NOT CURRENTLY IN USE. The number of attachment meshes */
|
/** The number of attachment meshes. Note! Currently only works with Collada loader. */
|
||||||
unsigned int mNumAnimMeshes;
|
unsigned int mNumAnimMeshes;
|
||||||
|
|
||||||
/** NOT CURRENTLY IN USE. Attachment meshes for this mesh, for vertex-based animation.
|
/** Attachment meshes for this mesh, for vertex-based animation.
|
||||||
* Attachment meshes carry replacement data for some of the
|
* Attachment meshes carry replacement data for some of the
|
||||||
* mesh'es vertex components (usually positions, normals). */
|
* mesh'es vertex components (usually positions, normals).
|
||||||
|
* Note! Currently only works with Collada loader.*/
|
||||||
C_STRUCT aiAnimMesh** mAnimMeshes;
|
C_STRUCT aiAnimMesh** mAnimMeshes;
|
||||||
|
|
||||||
|
/** Method of morphing when animeshes are specified. */
|
||||||
|
unsigned int mMethod;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
@ -733,7 +760,6 @@ struct aiMesh
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif //! extern "C"
|
#endif //! extern "C"
|
||||||
|
|
Loading…
Reference in New Issue