From 255082c39ba5939ebcf4bfa41dc9af10db2d74ac Mon Sep 17 00:00:00 2001 From: aramis_acg Date: Mon, 10 May 2010 18:05:52 +0000 Subject: [PATCH] Add data structures for vertex animation. Basing on recent ML discussion. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@720 67173fc5-114c-0410-ac8e-9d2fd5bffc1f --- include/aiAnim.h | 168 +++++++++++++++++++++++++++++++++++++++-------- include/aiMesh.h | 140 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 273 insertions(+), 35 deletions(-) diff --git a/include/aiAnim.h b/include/aiAnim.h index d377bd77e..828507c57 100644 --- a/include/aiAnim.h +++ b/include/aiAnim.h @@ -57,9 +57,10 @@ extern "C" { /** A time-value pair specifying a certain 3D vector for the given time. */ struct aiVectorKey { - //! The time of this key + /** The time of this key */ double mTime; - //! The value of this key + + /** The value of this key */ C_STRUCT aiVector3D mValue; #ifdef __cplusplus @@ -76,8 +77,7 @@ struct aiVectorKey typedef aiVector3D elem_type; - //! Comparison operators. Just the key value is compared - //! For use with std::find(); + // Comparison operators. For use with std::find(); bool operator == (const aiVectorKey& o) const { return o.mValue == this->mValue; } @@ -85,8 +85,7 @@ struct aiVectorKey return o.mValue != this->mValue; } - //! Relational operators. Just the key time is compared - //! For use with std::sort(); + // Relational operators. For use with std::sort(); bool operator < (const aiVectorKey& o) const { return mTime < o.mTime; } @@ -97,22 +96,21 @@ struct aiVectorKey }; // --------------------------------------------------------------------------- -/** A time-value pair specifying a rotation for the given time. For joint - * animations the rotation is usually expressed using a quaternion. - */ +/** A time-value pair specifying a rotation for the given time. + * Rotations are expressed with quaternions. */ struct aiQuatKey { - //! The time of this key + /** The time of this key */ double mTime; - //! The value of this key + + /** The value of this key */ C_STRUCT aiQuaternion mValue; #ifdef __cplusplus + aiQuatKey(){ + } - //! Default constructor - aiQuatKey(){} - - //! Construction from a given time and key value + /** Construction from a given time and key value */ aiQuatKey(double time, const aiQuaternion& value) : mTime (time) , mValue (value) @@ -120,8 +118,7 @@ struct aiQuatKey typedef aiQuaternion elem_type; - //! Comparison operators. Just the key value is compared - //! For use with std::find(); + // Comparison operators. For use with std::find(); bool operator == (const aiQuatKey& o) const { return o.mValue == this->mValue; } @@ -129,8 +126,7 @@ struct aiQuatKey return o.mValue != this->mValue; } - //! Relational operators. Just the key time is compared - //! For use with std::sort(); + // Relational operators. For use with std::sort(); bool operator < (const aiQuatKey& o) const { return mTime < o.mTime; } @@ -140,6 +136,51 @@ struct aiQuatKey #endif }; +// --------------------------------------------------------------------------- +/** Binds a anim mesh to a specific point in time. */ +struct aiMeshKey +{ + /** The time of this key */ + double mTime; + + /** Index into the aiMesh::mAnimMeshes array of the + * mesh coresponding to the #aiMeshAnim hosting this + * key frame. The referenced anim mesh is evaluated + * according to the rules defined in the docs for #aiAnimMesh.*/ + unsigned int mValue; + +#ifdef __cplusplus + + aiMeshKey() { + } + + /** Construction from a given time and key value */ + aiMeshKey(double time, const unsigned int value) + : mTime (time) + , mValue (value) + {} + + typedef unsigned int elem_type; + + // Comparison operators. For use with std::find(); + bool operator == (const aiMeshKey& o) const { + return o.mValue == this->mValue; + } + bool operator != (const aiMeshKey& o) const { + return o.mValue != this->mValue; + } + + // Relational operators. For use with std::sort(); + bool operator < (const aiMeshKey& o) const { + return mTime < o.mTime; + } + bool operator > (const aiMeshKey& o) const { + return mTime > o.mTime; + } + +#endif +}; + // --------------------------------------------------------------------------- /** Defines how an animation channel behaves outside the defined time * range. This corresponds to aiNodeAnim::mPreState and @@ -184,8 +225,8 @@ enum aiAnimBehaviour * * @note All keys are returned in their correct, chronological order. * Duplicate keys don't pass the validation step. Most likely there - * will be no negative time values, but they are not forbidden ( so you should - * be able to handle them ) */ + * will be no negative time values, but they are not forbidden also ( so + * implementations need to cope with them! ) */ struct aiNodeAnim { /** The name of the node affected by this animation. The node @@ -258,6 +299,41 @@ struct aiNodeAnim #endif // __cplusplus }; +// --------------------------------------------------------------------------- +/** Describes vertex-based animations for a single mesh or a group of + * meshes. Meshes carry the animation data for each frame in their + * aiMesh::mAnimMeshes array. The purpose of aiMeshAnim is to + * define keyframes linking each mesh attachment to a particular + * point in time. */ +struct aiMeshAnim +{ + /** 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 aiMeshKey* mKeys; + +#ifdef __cplusplus + + aiMeshAnim() + : mNumKeys() + , mKeys() + {} + + ~aiMeshAnim() + { + delete[] mKeys; + } + +#endif +}; + // --------------------------------------------------------------------------- /** An animation consists of keyframe data for a number of nodes. For * each node affected by the animation a separate series of data is given.*/ @@ -282,24 +358,43 @@ struct aiAnimation * The array is mNumChannels in size. */ C_STRUCT aiNodeAnim** mChannels; + + /** The number of mesh animation channels. Each channel affects + * a single mesh and defines vertex-based animation. */ + unsigned int mNumMeshChannels; + + /** The mesh animation channels. Each channel affects a single mesh. + * The array is mNumMeshChannels in size. */ + C_STRUCT aiMeshAnim** mMeshChannels; + #ifdef __cplusplus aiAnimation() + : mDuration(-1.) + , mTicksPerSecond() + , mNumChannels() + , mChannels() + , mNumMeshChannels() + , mMeshChannels() { - mDuration = -1.; - mTicksPerSecond = 0; - mNumChannels = 0; mChannels = NULL; } ~aiAnimation() { // DO NOT REMOVE THIS ADDITIONAL CHECK - if (mNumChannels && mChannels) - { - for( unsigned int a = 0; a < mNumChannels; a++) + if (mNumChannels && mChannels) { + for( unsigned int a = 0; a < mNumChannels; a++) { delete mChannels[a]; + } delete [] mChannels; } + if (mNumMeshChannels && mMeshChannels) { + for( unsigned int a = 0; a < mNumMeshChannels; a++) { + delete mMeshChannels[a]; + } + + delete [] mMeshChannels; + } } #endif // __cplusplus }; @@ -341,6 +436,15 @@ struct Interpolator { } }; // ! Interpolator +template <> +struct Interpolator { + void operator () (unsigned int& out,unsigned int a, + unsigned int b, float d) const + { + out = d>0.5f ? b : a; + } +}; // ! Interpolator + template <> struct Interpolator { void operator () (aiVector3D& out,const aiVectorKey& a, @@ -361,6 +465,16 @@ struct Interpolator { } }; // ! Interpolator +template <> +struct Interpolator { + void operator () (unsigned int& out, const aiMeshKey a, + const aiMeshKey& b, float d) const + { + Interpolator ipl; + ipl(out,a.mValue,b.mValue,d); + } +}; // ! Interpolator + //! @endcond } // ! end namespace Assimp diff --git a/include/aiMesh.h b/include/aiMesh.h index 14cce69fa..b15ddb7fd 100644 --- a/include/aiMesh.h +++ b/include/aiMesh.h @@ -302,6 +302,110 @@ enum aiPrimitiveType #define AI_PRIMITIVE_TYPE_FOR_N_INDICES(n) \ ((n) > 3 ? aiPrimitiveType_POLYGON : (aiPrimitiveType)(1u << ((n)-1))) + +// --------------------------------------------------------------------------- +/** @brief An AnimMesh is an attachment to an #aiMesh stores per-vertex + * animations for a particular frame. + * + * You may think of an #aiAnimMesh as a `patch` for the host mesh, which + * replaces only certain vertex data streams at a particular time. + * Each mesh stores n attached attached meshes (#aiMesh::mAnimMeshes). + * The actual relationship between the time line and anim meshes is + * established by #aiMeshAnim, which references singular mesh attachments + * by their ID and binds them to a time offset. +*/ +struct aiAnimMesh +{ + /** Replacement for aiMesh::mVertices. If this array is non-NULL, + * it *must* contain aiMesh::mNumVertices entries. The corresponding + * array in the host mesh must be non-NULL as well - animation + * meshes may neither add or nor remove vertex components (if + * a replacement array is NULL and the corresponding source + * array is not, the source data is taken instead)*/ + C_STRUCT aiVector3D* mVertices; + + /** Replacement for aiMesh::mNormals. */ + C_STRUCT aiVector3D* mNormals; + + /** Replacement for aiMesh::mTangents. */ + C_STRUCT aiVector3D* mTangents; + + /** Replacement for aiMesh::mBitangents. */ + C_STRUCT aiVector3D* mBitangents; + + /** Replacement for aiMesh::mColors */ + C_STRUCT aiColor4D* mColors[AI_MAX_NUMBER_OF_COLOR_SETS]; + + /** Replacement for aiMesh::mTextureCoords */ + C_STRUCT aiVector3D* mTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; + +#ifdef __cplusplus + + aiAnimMesh() + : mVertices() + , mNormals() + , mTangents() + , mBitangents() + { + // fixme consider moving this to the ctor initializer list as well + for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++){ + mTextureCoords[a] = NULL; + } + for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) { + mColors[a] = NULL; + } + } + + ~aiAnimMesh() + { + delete [] mVertices; + delete [] mNormals; + delete [] mTangents; + delete [] mBitangents; + for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) { + delete [] mTextureCoords[a]; + } + for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) { + delete [] mColors[a]; + } + } + + /** Check whether the anim mesh overrides the vertex positions + * of its host mesh*/ + bool HasPositions() const { + return mVertices != NULL; + } + + /** Check whether the anim mesh overrides the vertex normals + * of its host mesh*/ + bool HasNormals() const { + return mNormals != NULL; + } + + /** Check whether the anim mesh overrides the vertex tangents + * and bitangents of its host mesh. As for aiMesh, + * tangents and bitangents always go together. */ + bool HasTangentsAndBitangents() const { + return mTangents != NULL; + } + + /** Check whether the anim mesh overrides a particular + * set of vertex colors on his host mesh. + * @param pIndex 0= AI_MAX_NUMBER_OF_COLOR_SETS ? false : mColors[pIndex] != NULL; + } + + /** Check whether the anim mesh overrides a particular + * set of texture coordinates on his host mesh. + * @param pIndex 0= AI_MAX_NUMBER_OF_TEXTURECOORDS ? false : mTextureCoords[pIndex] != NULL; + } + +#endif +}; + // --------------------------------------------------------------------------- /** @brief A mesh represents a geometry or model with a single material. * @@ -453,6 +557,14 @@ struct aiMesh **/ aiString mName; + /** The number of attachment meshes */ + unsigned int mNumAnimMeshes; + + /** Attachment meshes for this mesh, for vertex-based animation. + * Attachment meshes carry replacement data for some of the + * mesh'es vertex components (usually positions, normals). */ + C_STRUCT aiAnimMesh** mAnimMeshes; + #ifdef __cplusplus //! Default constructor. Initializes all members to 0 @@ -460,10 +572,12 @@ struct aiMesh { mNumVertices = 0; mNumFaces = 0; + mNumAnimMeshes = 0; mPrimitiveTypes = 0; mVertices = NULL; mFaces = NULL; mNormals = NULL; mTangents = NULL; mBitangents = NULL; + mAnimMeshes = NULL; for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) { mNumUVComponents[a] = 0; @@ -482,24 +596,33 @@ struct aiMesh delete [] mNormals; delete [] mTangents; delete [] mBitangents; - for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) + for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) { delete [] mTextureCoords[a]; - for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) + } + for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) { delete [] mColors[a]; + } // DO NOT REMOVE THIS ADDITIONAL CHECK - if (mNumBones && mBones) - { - for( unsigned int a = 0; a < mNumBones; a++) + if (mNumBones && mBones) { + for( unsigned int a = 0; a < mNumBones; a++) { delete mBones[a]; + } delete [] mBones; } + if (mNumAnimMeshes && mAnimMeshes) { + for( unsigned int a = 0; a < mNumAnimMeshes; a++) { + delete mAnimMeshes[a]; + } + delete [] mBones; + } + delete [] mFaces; } - //! Check whether the mesh contains positions. If no special scene flags - //! (such as AI_SCENE_FLAGS_ANIM_SKELETON_ONLY) are set this will - //! always return true + //! Check whether the mesh contains positions. Provided no special + //! scene flags are set (such as AI_SCENE_FLAGS_ANIM_SKELETON_ONLY), + //! this will always be true bool HasPositions() const { return mVertices != NULL && mNumVertices > 0; } @@ -562,6 +685,7 @@ struct aiMesh #endif // __cplusplus }; + #ifdef __cplusplus } #endif //! extern "C"