ASE: Added WIP support for *SMOOTHSKINMESH elements in ASE/ASC files. Fixes in the ASE loader. Fixed animation parsing. Temporary implementation of target lights and cameras, including animations.

3DS: Fixed transformation problems (Pivot points), added WIP animation support. No target animation yet (cameras, spot lights). Not yet fully tested, but static models that worked before should still work now, except all look correct now :-) (some problems with very large models remaining)
Further work on the IRR and IRRMESH loaders. IRR still WIP, IRRMESH more stable now.
Work on the LWo loader. Added support for the "one-layer-only" mode. Hierarchy bug still unfixed, UV coords bug still unfixed.
Further work on the FindInvalidDataprocess. Improved validation for normals, no false positives anymore.
Further work on the MDR loader, still WIP.
Moved DeterminePType-Step to ScenePreprocessor.
aiAnimation::mDuration is optional now, ScenePreprocessor computes it automatically if set to -1.
Fixes in the SMD loader. Still crashes on some files.
Updated animation documentation.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@236 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/1/head
aramis_acg 2008-11-09 23:17:19 +00:00
parent 06e4262f80
commit f7aa836330
50 changed files with 4252 additions and 737 deletions

View File

@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// internal headers // internal headers
#include "3DSLoader.h" #include "3DSLoader.h"
#include "TextureTransform.h" #include "TextureTransform.h"
#include "TargetAnimation.h"
using namespace Assimp; using namespace Assimp;
@ -528,7 +529,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Nod
aiMatrix4x4 abs; aiMatrix4x4 abs;
if (pcIn->mName == "$$$DUMMY") if (pcIn->mName == "$$$DUMMY")
{ {
// append the "real" name of the dummy to the string // Append the "real" name of the dummy to the string
pcIn->mName.append(pcIn->mDummyName); pcIn->mName.append(pcIn->mDummyName);
} }
else // if (pcIn->mName != "$$$DUMMY") else // if (pcIn->mName != "$$$DUMMY")
@ -538,25 +539,18 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Nod
const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0]; const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0];
ai_assert(NULL != pcMesh); ai_assert(NULL != pcMesh);
// do case independent comparisons here, just for safety if (pcIn->mName == pcMesh->mName)
if (!ASSIMP_stricmp(pcIn->mName,pcMesh->mName))
iArray.push_back(a); iArray.push_back(a);
} }
if (!iArray.empty()) if (!iArray.empty())
{ {
// The matrix should be identical for all meshes. // The matrix should be identical for all meshes with the same name.
// It HAS to be identical for all meshes ........ // It HAS to be identical for all meshes ........
aiMatrix4x4& mTrafo = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0])->mMat; aiMatrix4x4& mTrafo = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0])->mMat;
aiMatrix4x4 mInv = mTrafo; aiMatrix4x4 mInv = mTrafo;
if (!configSkipPivot) if (!configSkipPivot)
mInv.Inverse(); mInv.Inverse();
/* abs = mTrafo;
pcOut->mTransformation = absTrafo;
pcOut->mTransformation = pcOut->mTransformation.Inverse() * mTrafo;
const aiVector3D& pivot = pcIn->vPivot;
aiMatrix4x4 trans;
*/
const aiVector3D& pivot = pcIn->vPivot; const aiVector3D& pivot = pcIn->vPivot;
pcOut->mNumMeshes = (unsigned int)iArray.size(); pcOut->mNumMeshes = (unsigned int)iArray.size();
@ -566,7 +560,8 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Nod
const unsigned int iIndex = iArray[i]; const unsigned int iIndex = iArray[i];
aiMesh* const mesh = pcSOut->mMeshes[iIndex]; aiMesh* const mesh = pcSOut->mMeshes[iIndex];
// http://www.zfx.info/DisplayThread.php?MID=235690#235690 // Pivot point adjustment.
// See: http://www.zfx.info/DisplayThread.php?MID=235690#235690
const aiVector3D* const pvEnd = mesh->mVertices+mesh->mNumVertices; const aiVector3D* const pvEnd = mesh->mVertices+mesh->mNumVertices;
aiVector3D* pvCurrent = mesh->mVertices; aiVector3D* pvCurrent = mesh->mVertices;
@ -578,11 +573,9 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Nod
pvCurrent->x -= pivot.x; pvCurrent->x -= pivot.x;
pvCurrent->y -= pivot.y; pvCurrent->y -= pivot.y;
pvCurrent->z -= pivot.z; pvCurrent->z -= pivot.z;
*pvCurrent = mTrafo * (*pvCurrent);
++pvCurrent; ++pvCurrent;
} }
} }
#if 0
else else
{ {
while (pvCurrent != pvEnd) while (pvCurrent != pvEnd)
@ -591,7 +584,6 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Nod
++pvCurrent; ++pvCurrent;
} }
} }
#endif
// Setup the mesh index // Setup the mesh index
pcOut->mMeshes[i] = iIndex; pcOut->mMeshes[i] = iIndex;
@ -599,63 +591,130 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Nod
} }
} }
// Now build the transformation matrix of the node
// ROTATION
if (pcIn->aRotationKeys.size())
{
pcOut->mTransformation = aiMatrix4x4( pcIn->aRotationKeys[0].mValue.GetMatrix() );
}
else if (pcIn->aCameraRollKeys.size())
{
aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(- pcIn->aCameraRollKeys[0].mValue),
pcOut->mTransformation);
}
// SCALING
aiMatrix4x4& m = pcOut->mTransformation;
if (pcIn->aScalingKeys.size())
{
const aiVector3D& v = pcIn->aScalingKeys[0].mValue;
m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x;
m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y;
m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z;
}
// TRANSLATION
if (pcIn->aPositionKeys.size())
{
const aiVector3D& v = pcIn->aPositionKeys[0].mValue;
m.a4 += v.x;
m.b4 += v.y;
m.c4 += v.z;
}
// Generate animation channels for the node // Generate animation channels for the node
if (pcIn->aPositionKeys.size() > 0 || pcIn->aRotationKeys.size() > 0 || if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 ||
pcIn->aScalingKeys.size() > 0 || pcIn->aCameraRollKeys.size() > 0 || pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 ||
pcIn->aTargetPositionKeys.size() > 0) pcIn->aTargetPositionKeys.size() > 1)
{ {
aiAnimation* anim = pcSOut->mAnimations[0]; aiAnimation* anim = pcSOut->mAnimations[0];
ai_assert(NULL != anim); ai_assert(NULL != anim);
// Allocate a new channel, increment the channel index if (pcIn->aCameraRollKeys.size() > 1)
aiNodeAnim* channel = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); {
DefaultLogger::get()->debug("3DS: Converting camera roll track ...");
// Camera roll keys - in fact they're just rotations
// around the camera's z axis. The angles are given
// in degrees (and they're clockwise).
pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size());
for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i)
{
aiQuatKey& q = pcIn->aRotationKeys[i];
aiFloatKey& f = pcIn->aCameraRollKeys[i];
q.mTime = f.mTime;
q.mValue = aiQuaternion(0.f,0.f,AI_DEG_TO_RAD(- f.mValue));
}
}
if (pcIn->aTargetPositionKeys.size() > 1)
{
//DefaultLogger::get()->debug("3DS: Converting target track ...");
//// Camera or spot light - need to convert the separate
//// target position channel to our representation
//TargetAnimationHelper helper;
//helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys);
//helper.SetMainAnimationChannel(&pcIn->aPositionKeys);
//// Do the conversion
//std::vector<aiVectorKey> distanceTrack;
//helper.Process(&distanceTrack);
//// Now add a new node as child, name it <ourName>.Target
//// and assign the distance track to it. This is that the
//// information where the target is and how it moves is
//// not lost
//D3DS::Node* nd = new D3DS::Node();
//pcIn->push_back(nd);
//nd->mName = pcIn->mName + ".Target";
//aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
//nda->mNodeName.Set(nd->mName);
//nda->mNumPositionKeys = (unsigned int)distanceTrack.size();
//nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
//::memcpy(nda->mPositionKeys,&distanceTrack[0],
// sizeof(aiVectorKey)*nda->mNumPositionKeys);
}
// Just for safety ... we *should* have at least one track here
if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 ||
pcIn->aScalingKeys.size() > 1)
{
// Allocate a new nda, increment the nda index
aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
nda->mNodeName.Set(pcIn->mName);
// POSITION keys // POSITION keys
if (pcIn->aPositionKeys.size() > 0) if (pcIn->aPositionKeys.size() > 0)
{ {
// Sort all keys with ascending time values nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size();
std::sort(pcIn->aPositionKeys.begin(),pcIn->aPositionKeys.end()); nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0],
channel->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size(); sizeof(aiVectorKey)*nda->mNumPositionKeys);
channel->mPositionKeys = new aiVectorKey[channel->mNumPositionKeys];
::memcpy(channel->mPositionKeys,&pcIn->aPositionKeys[0],
sizeof(aiVectorKey)*channel->mNumPositionKeys);
// Get the maximum key
anim->mDuration = std::max(anim->mDuration,channel->
mPositionKeys[channel->mNumPositionKeys-1].mTime);
} }
// ROTATION keys // ROTATION keys
if (pcIn->aRotationKeys.size() > 0) if (pcIn->aRotationKeys.size() > 0)
{ {
// Sort all keys with ascending time values nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size();
std::sort(pcIn->aRotationKeys.begin(),pcIn->aRotationKeys.end()); nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys];
::memcpy(nda->mRotationKeys,&pcIn->aRotationKeys[0],
channel->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size(); sizeof(aiQuatKey)*nda->mNumRotationKeys);
channel->mRotationKeys = new aiQuatKey[channel->mNumRotationKeys];
::memcpy(channel->mRotationKeys,&pcIn->aRotationKeys[0],
sizeof(aiQuatKey)*channel->mNumRotationKeys);
// Get the maximum key
anim->mDuration = std::max(anim->mDuration,channel->
mRotationKeys[channel->mNumRotationKeys-1].mTime);
} }
// SCALING keys // SCALING keys
if (pcIn->aScalingKeys.size() > 0) if (pcIn->aScalingKeys.size() > 0)
{ {
// Sort all keys with ascending time values nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size();
std::sort(pcIn->aScalingKeys.begin(),pcIn->aScalingKeys.end()); nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys];
::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0],
channel->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size(); sizeof(aiVectorKey)*nda->mNumScalingKeys);
channel->mScalingKeys = new aiVectorKey[channel->mNumScalingKeys]; }
::memcpy(channel->mScalingKeys,&pcIn->aScalingKeys[0],
sizeof(aiVectorKey)*channel->mNumScalingKeys);
// Get the maximum key
anim->mDuration = std::max(anim->mDuration,channel->
mScalingKeys[channel->mNumScalingKeys-1].mTime);
} }
} }
@ -667,7 +726,8 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Nod
pcOut->mChildren = new aiNode*[pcIn->mChildren.size()]; pcOut->mChildren = new aiNode*[pcIn->mChildren.size()];
// Recursively process all children // Recursively process all children
for (unsigned int i = 0; i < pcIn->mChildren.size();++i) const unsigned int size = pcIn->mChildren.size();
for (unsigned int i = 0; i < size;++i)
{ {
pcOut->mChildren[i] = new aiNode(); pcOut->mChildren[i] = new aiNode();
pcOut->mChildren[i]->mParent = pcOut; pcOut->mChildren[i]->mParent = pcOut;
@ -683,11 +743,13 @@ void CountTracks(D3DS::Node* node, unsigned int& cnt)
// We will never generate more than one channel for a node, so // We will never generate more than one channel for a node, so
// this is rather easy here. // this is rather easy here.
if (node->aPositionKeys.size() > 0 || node->aRotationKeys.size() > 0 || if (node->aPositionKeys.size() > 1 || node->aRotationKeys.size() > 1 ||
node->aScalingKeys.size() > 0 || node->aCameraRollKeys.size() > 0 || node->aScalingKeys.size() > 1 || node->aCameraRollKeys.size() > 1 ||
node->aTargetPositionKeys.size() > 0) node->aTargetPositionKeys.size() > 1)
{ {
++cnt; ++cnt;
if (node->aTargetPositionKeys.size() > 1)++cnt;
} }
// Recursively process all children // Recursively process all children
@ -778,6 +840,14 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
aiMatrix4x4 m; aiMatrix4x4 m;
AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode,m); AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode,m);
// If the root node is unnamed name it "<3DSRoot>"
if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" )
|| pcOut->mRootNode->mName.data[0] == '$'
&& pcOut->mRootNode->mName.data[1] == '$')
{
pcOut->mRootNode->mName.Set("<3DSRoot>");
}
} }
// We used the first vertex color set to store some // We used the first vertex color set to store some
@ -795,10 +865,6 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
delete pcOld; delete pcOld;
} }
// if the root node is a default node setup a name for it
if (pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$')
pcOut->mRootNode->mName.Set("<root>");
#if 0 #if 0
// modify the transformation of the root node to change // modify the transformation of the root node to change
// the coordinate system of the whole scene from Max' to OpenGL // the coordinate system of the whole scene from Max' to OpenGL

View File

@ -423,6 +423,7 @@ struct Mesh : public MeshWithSmoothingGroups<D3DS::Face>
{ {
static int iCnt = 0; static int iCnt = 0;
// Generate a default name for the mesh
char szTemp[128]; char szTemp[128];
::sprintf(szTemp,"UNNAMED_%i",iCnt++); ::sprintf(szTemp,"UNNAMED_%i",iCnt++);
mName = szTemp; mName = szTemp;
@ -441,7 +442,30 @@ struct Mesh : public MeshWithSmoothingGroups<D3DS::Face>
aiMatrix4x4 mMat; aiMatrix4x4 mMat;
}; };
typedef std::pair<double, float> aiFloatKey; // ---------------------------------------------------------------------------
/** Float key - quite similar to aiVectorKey and aiQuatKey. Both are in the
C-API, so it would be difficult to make them a template. */
struct aiFloatKey
{
double mTime; ///< The time of this key
float mValue; ///< The value of this key
#ifdef __cplusplus
// time is not compared
bool operator == (const aiFloatKey& o) const
{return o.mValue == this->mValue;}
bool operator != (const aiFloatKey& o) const
{return o.mValue != this->mValue;}
// Only time is compared. This operator is defined
// for use with std::sort
bool operator < (const aiFloatKey& o) const
{return mTime < o.mTime;}
#endif
};
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** Helper structure to represent a 3ds file node */ /** Helper structure to represent a 3ds file node */
@ -449,11 +473,13 @@ struct Node
{ {
Node() Node()
: mHierarchyPos(0),mHierarchyIndex(0) : mHierarchyPos (0)
, mHierarchyIndex (0)
{ {
static int iCnt = 0; static int iCnt = 0;
// Generate a default name for the node
char szTemp[128]; char szTemp[128];
::sprintf(szTemp,"UNNAMED_%i",iCnt++); ::sprintf(szTemp,"UNNAMED_%i",iCnt++);
mName = szTemp; mName = szTemp;
@ -463,6 +489,12 @@ struct Node
aScalingKeys.reserve (20); aScalingKeys.reserve (20);
} }
~Node()
{
for (unsigned int i = 0; i < mChildren.size();++i)
delete mChildren[i];
}
//! Pointer to the parent node //! Pointer to the parent node
Node* mParent; Node* mParent;
@ -481,7 +513,6 @@ struct Node
//! Index of the node //! Index of the node
int16_t mHierarchyIndex; int16_t mHierarchyIndex;
//! Rotation keys loaded from the file //! Rotation keys loaded from the file
std::vector<aiQuatKey> aRotationKeys; std::vector<aiQuatKey> aRotationKeys;
@ -508,7 +539,6 @@ struct Node
{ {
mChildren.push_back(pc); mChildren.push_back(pc);
pc->mParent = this; pc->mParent = this;
//pc->mHierarchyPos = this->mHierarchyPos+1;
return *this; return *this;
} }
}; };
@ -516,7 +546,6 @@ struct Node
/** Helper structure analogue to aiScene */ /** Helper structure analogue to aiScene */
struct Scene struct Scene
{ {
//! List of all materials loaded //! List of all materials loaded
//! NOTE: 3ds references materials globally //! NOTE: 3ds references materials globally
std::vector<Material> mMaterials; std::vector<Material> mMaterials;
@ -531,7 +560,8 @@ struct Scene
std::vector<aiLight*> mLights; std::vector<aiLight*> mLights;
//! Pointer to the root node of the scene //! Pointer to the root node of the scene
Node* pcRootNode; // --- moved to main class
// Node* pcRootNode;
}; };

View File

@ -169,8 +169,14 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
// Now apply the master scaling factor to the scene // Now apply the master scaling factor to the scene
ApplyMasterScale(pScene); ApplyMasterScale(pScene);
// We're finished here. Everything destructs automatically // Delete our internal scene representation and the root
// and the output scene should be valid. // node, so the whole hierarchy will follow
delete mRootNode;
delete mScene;
AI_DEBUG_INVALIDATE_PTR(mRootNode);
AI_DEBUG_INVALIDATE_PTR(mScene);
AI_DEBUG_INVALIDATE_PTR(this->stream);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -181,12 +187,14 @@ void Discreet3DSImporter::ApplyMasterScale(aiScene* pScene)
if (!mMasterScale)mMasterScale = 1.0f; if (!mMasterScale)mMasterScale = 1.0f;
else mMasterScale = 1.0f / mMasterScale; else mMasterScale = 1.0f / mMasterScale;
// construct an uniform scaling matrix and multiply with it // Construct an uniform scaling matrix and multiply with it
pScene->mRootNode->mTransformation *= aiMatrix4x4( pScene->mRootNode->mTransformation *= aiMatrix4x4(
mMasterScale,0.0f, 0.0f, 0.0f, mMasterScale,0.0f, 0.0f, 0.0f,
0.0f, mMasterScale,0.0f, 0.0f, 0.0f, mMasterScale,0.0f, 0.0f,
0.0f, 0.0f, mMasterScale,0.0f, 0.0f, 0.0f, mMasterScale,0.0f,
0.0f, 0.0f, 0.0f, 1.0f); 0.0f, 0.0f, 0.0f, 1.0f);
// Check whether a scaling track is assigned to the root node.
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -416,6 +424,11 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
camera->mName.Set(std::string(name, num)); camera->mName.Set(std::string(name, num));
// The camera position and look-at vector are
// difficult to handle. Later we'll copy these
// values to the local transformation of the
// camera's node.
// First read the position of the camera // First read the position of the camera
camera->mPosition.x = stream->GetF4(); camera->mPosition.x = stream->GetF4();
camera->mPosition.y = stream->GetF4(); camera->mPosition.y = stream->GetF4();
@ -540,6 +553,14 @@ D3DS::Node* FindNode(D3DS::Node* root, const std::string& name)
return NULL; return NULL;
} }
// ------------------------------------------------------------------------------------------------
// Binary predicate for std::unique()
template <class T>
bool KeyUniqueCompare(const T& first, const T& second)
{
return first.mTime == second.mTime;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent) void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
{ {
@ -638,11 +659,14 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
break; break;
// **************************************************************
// POSITION KEYFRAME
case Discreet3DS::CHUNK_TRACKPOS: case Discreet3DS::CHUNK_TRACKPOS:
{ {
stream->IncPtr(10); stream->IncPtr(10);
unsigned int numFrames = stream->GetI2(); unsigned int numFrames = stream->GetI2();
stream->IncPtr(2); stream->IncPtr(2);
bool sortKeys = false;
// This could also be meant as the target position for // This could also be meant as the target position for
// (targeted) lights and cameras // (targeted) lights and cameras
@ -667,22 +691,26 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
v.mValue.y = stream->GetF4(); v.mValue.y = stream->GetF4();
v.mValue.z = stream->GetF4(); v.mValue.z = stream->GetF4();
// Check whether we do already have this keyframe // check whether we'll need to sort the keys
for (std::vector<aiVectorKey>::const_iterator if (!l->empty() && v.mTime <= l->back().mTime)
i = l->begin();i != l->end();++i) sortKeys = true;
{
if ((*i).mTime == v.mTime)
{
DefaultLogger::get()->error("3DS: Found duplicate position keyframe");
v.mTime = -10e10f;
break;
}
}
// Add the new keyframe to the list // Add the new keyframe to the list
if (v.mTime != -10e10f)l->push_back(v); l->push_back(v);
}
// Sort all keys with ascending time values?
if (sortKeys)
{
std::sort (l->begin(),l->end());
std::unique (l->begin(),l->end(),
std::ptr_fun(&KeyUniqueCompare<aiVectorKey>));
}} }}
break; break;
// **************************************************************
// CAMERA ROLL KEYFRAME
case Discreet3DS::CHUNK_TRACKROLL: case Discreet3DS::CHUNK_TRACKROLL:
{ {
// roll keys are accepted for cameras only // roll keys are accepted for cameras only
@ -691,6 +719,8 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
DefaultLogger::get()->warn("3DS: Ignoring roll track for non-camera object"); DefaultLogger::get()->warn("3DS: Ignoring roll track for non-camera object");
break; break;
} }
bool sortKeys = false;
std::vector<aiFloatKey>* l = &mCurrentNode->aCameraRollKeys;
stream->IncPtr(10); stream->IncPtr(10);
unsigned int numFrames = stream->GetI2(); unsigned int numFrames = stream->GetI2();
@ -702,40 +732,57 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
// Setup a new position key // Setup a new position key
aiFloatKey v; aiFloatKey v;
v.first = (double)fidx; v.mTime = (double)fidx;
// This is just a single float // This is just a single float
stream->IncPtr(4); stream->IncPtr(4);
v.second = stream->GetF4(); v.mValue = stream->GetF4();
// Check whether we'll need to sort the keys
if (!l->empty() && v.mTime <= l->back().mTime)
sortKeys = true;
// Check whether we do already have this keyframe
for (std::vector<aiFloatKey>::const_iterator
i = mCurrentNode->aCameraRollKeys.begin();
i != mCurrentNode->aCameraRollKeys.end();++i)
{
if ((*i).first == v.first)
{
DefaultLogger::get()->error("3DS: Found duplicate camera roll keyframe");
v.first = -10e10f;
break;
}
}
// Add the new keyframe to the list // Add the new keyframe to the list
if (v.first != -10e10f) l->push_back(v);
mCurrentNode->aCameraRollKeys.push_back(v); }
// Sort all keys with ascending time values?
if (sortKeys)
{
std::sort (l->begin(),l->end());
std::unique (l->begin(),l->end(),
std::ptr_fun(&KeyUniqueCompare<aiFloatKey>));
}} }}
break; break;
// **************************************************************
// CAMERA FOV KEYFRAME
case Discreet3DS::CHUNK_TRACKFOV:
{
DefaultLogger::get()->error("3DS: Skipping FOV animation track. "
"This is not supported");
}
break;
// **************************************************************
// ROTATION KEYFRAME
case Discreet3DS::CHUNK_TRACKROTATE: case Discreet3DS::CHUNK_TRACKROTATE:
{ {
stream->IncPtr(10); stream->IncPtr(10);
unsigned int numFrames = stream->GetI2(); unsigned int numFrames = stream->GetI2();
stream->IncPtr(2); stream->IncPtr(2);
bool sortKeys = false;
std::vector<aiQuatKey>* l = &mCurrentNode->aRotationKeys;
for (unsigned int i = 0; i < numFrames;++i) for (unsigned int i = 0; i < numFrames;++i)
{ {
unsigned int fidx = stream->GetI2(); unsigned int fidx = stream->GetI2();
stream->IncPtr(4);
aiQuatKey v; aiQuatKey v;
v.mTime = (double)fidx; v.mTime = (double)fidx;
@ -746,38 +793,43 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
axis.y = stream->GetF4(); axis.y = stream->GetF4();
axis.z = stream->GetF4(); axis.z = stream->GetF4();
if (!axis.x && !axis.y && !axis.z)
axis.y = 1.f;
// Construct a rotation quaternion from the axis-angle pair // Construct a rotation quaternion from the axis-angle pair
v.mValue = aiQuaternion(axis,rad); v.mValue = aiQuaternion(axis,rad);
// check whether we do already have this keyframe // Check whether we'll need to sort the keys
for (std::vector<aiQuatKey>::const_iterator if (!l->empty() && v.mTime <= l->back().mTime)
i = mCurrentNode->aRotationKeys.begin(); sortKeys = true;
i != mCurrentNode->aRotationKeys.end();++i)
{
if ((*i).mTime == v.mTime)
{
DefaultLogger::get()->error("3DS: Found duplicate rotation keyframe");
v.mTime = -10e10f;
break;
}
}
// add the new keyframe to the list // add the new keyframe to the list
if (v.mTime != -10e10f) l->push_back(v);
mCurrentNode->aRotationKeys.push_back(v); }
// Sort all keys with ascending time values?
if (sortKeys)
{
std::sort (l->begin(),l->end());
std::unique (l->begin(),l->end(),
std::ptr_fun(&KeyUniqueCompare<aiQuatKey>));
}} }}
break; break;
// **************************************************************
// SCALING KEYFRAME
case Discreet3DS::CHUNK_TRACKSCALE: case Discreet3DS::CHUNK_TRACKSCALE:
{ {
unsigned int invalid = 0;
stream->IncPtr(10); stream->IncPtr(10);
unsigned int numFrames = stream->GetI2(); unsigned int numFrames = stream->GetI2();
stream->IncPtr(2); stream->IncPtr(2);
bool sortKeys = false;
std::vector<aiVectorKey>* l = &mCurrentNode->aScalingKeys;
for (unsigned int i = 0; i < numFrames;++i) for (unsigned int i = 0; i < numFrames;++i)
{ {
unsigned int fidx = stream->GetI2(); unsigned int fidx = stream->GetI2();
stream->IncPtr(4);
// Setup a new key // Setup a new key
aiVectorKey v; aiVectorKey v;
@ -788,34 +840,23 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
v.mValue.y = stream->GetF4(); v.mValue.y = stream->GetF4();
v.mValue.z = stream->GetF4(); v.mValue.z = stream->GetF4();
// check whether we do already have this keyframe // check whether we'll need to sort the keys
for (std::vector<aiVectorKey>::const_iterator if (!l->empty() && v.mTime <= l->back().mTime)
i = mCurrentNode->aScalingKeys.begin(); sortKeys = true;
i != mCurrentNode->aScalingKeys.end();++i)
{
if ((*i).mTime == v.mTime)
{
DefaultLogger::get()->error("3DS: Found duplicate scaling keyframe");
v.mTime = -10e10f;
break;
}
}
// add the new keyframe
if (v.mTime != -10e10f)
mCurrentNode->aScalingKeys.push_back(v);
// Check whether this is a zero scaling keyframe // Remove zero-scalings
if (!v.mValue.x && !v.mValue.y && !v.mValue.z) if (!v.mValue.x)v.mValue.x = 1.f;
{ if (!v.mValue.y)v.mValue.y = 1.f;
DefaultLogger::get()->warn("3DS: Found zero scaled axis in scaling keyframe"); if (!v.mValue.z)v.mValue.z = 1.f;
++invalid;
l->push_back(v);
} }
} // Sort all keys with ascending time values?
// there are 3DS files that have only zero scalings if (sortKeys)
if (numFrames == invalid)
{ {
DefaultLogger::get()->warn("3DS: All scaling keys are zero. Ignoring them ..."); std::sort (l->begin(),l->end());
mCurrentNode->aScalingKeys.clear(); std::unique (l->begin(),l->end(),
std::ptr_fun(&KeyUniqueCompare<aiVectorKey>));
}} }}
break; break;
}; };
@ -874,10 +915,12 @@ void Discreet3DSImporter::ParseFaceChunk()
{ {
DefaultLogger::get()->error(std::string("3DS: Unknown material: ") + sz); DefaultLogger::get()->error(std::string("3DS: Unknown material: ") + sz);
// *********************************************************
// This material is not known. Ignore this. We will later // This material is not known. Ignore this. We will later
// assign the default material to all faces using *this* // assign the default material to all faces using *this*
// material. Use 0xcdcdcdcd as special value to indicate // material. Use 0xcdcdcdcd as special value to indicate
// this. // this.
// *********************************************************
} }
// Now continue and read all material indices // Now continue and read all material indices

View File

@ -77,6 +77,7 @@ bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
// no file extension - can't read // no file extension - can't read
if( pos == std::string::npos) if( pos == std::string::npos)
return false; return false;
std::string extension = pFile.substr( pos); std::string extension = pFile.substr( pos);
// Either ASE, ASC or ASK // Either ASE, ASC or ASK
@ -109,7 +110,7 @@ void ASEImporter::InternReadFile( const std::string& pFile,
size_t fileSize = file->FileSize(); size_t fileSize = file->FileSize();
// allocate storage and copy the contents of the file to a memory buffer // Allocate storage and copy the contents of the file to a memory buffer
// (terminate it with zero) // (terminate it with zero)
std::vector<char> mBuffer2(fileSize+1); std::vector<char> mBuffer2(fileSize+1);
file->Read( &mBuffer2[0], 1, fileSize); file->Read( &mBuffer2[0], 1, fileSize);
@ -118,17 +119,35 @@ void ASEImporter::InternReadFile( const std::string& pFile,
this->mBuffer = &mBuffer2[0]; this->mBuffer = &mBuffer2[0];
this->pcScene = pScene; this->pcScene = pScene;
// construct an ASE parser and parse the file // *****************************************************************
// TODO: clean this up, mParser should be a reference, not a pointer ... // Guess the file format by looking at the extension
ASE::Parser parser(this->mBuffer); // ASC is considered to be the older format 110,
// ASE is the actual version 200 (that is currently written by max)
// *****************************************************************
unsigned int defaultFormat;
std::string::size_type s = pFile.length()-1;
switch (pFile.c_str()[s])
{
case 'C':
case 'c':
defaultFormat = AI_ASE_OLD_FILE_FORMAT;
break;
default:
defaultFormat = AI_ASE_NEW_FILE_FORMAT;
};
// Construct an ASE parser and parse the file
ASE::Parser parser(mBuffer,defaultFormat);
mParser = &parser; mParser = &parser;
mParser->Parse(); mParser->Parse();
// *****************************************************************
// Check whether we loaded at least one mesh. If we did - generate // Check whether we loaded at least one mesh. If we did - generate
// materials and copy meshes. // materials and copy meshes.
// *****************************************************************
if ( !mParser->m_vMeshes.empty()) if ( !mParser->m_vMeshes.empty())
{ {
// if absolutely no material has been loaded from the file // If absolutely no material has been loaded from the file
// we need to generate a default material // we need to generate a default material
GenerateDefaultMaterial(); GenerateDefaultMaterial();
@ -142,16 +161,16 @@ void ASEImporter::InternReadFile( const std::string& pFile,
{ {
if ((*i).bSkip)continue; if ((*i).bSkip)continue;
// now we need to create proper meshes from the import we // Now we need to create proper meshes from the import we
// need to split them by materials, build valid vertex/ // need to split them by materials, build valid vertex/
// face lists ... // face lists ...
BuildUniqueRepresentation(*i); BuildUniqueRepresentation(*i);
// need to generate proper vertex normals if necessary // Need to generate proper vertex normals if necessary
if(GenerateNormals(*i)) if(GenerateNormals(*i))
tookNormals = true; tookNormals = true;
// convert all meshes to aiMesh objects // Convert all meshes to aiMesh objects
ConvertMeshes(*i,avOutMeshes); ConvertMeshes(*i,avOutMeshes);
} }
if (tookNormals) if (tookNormals)
@ -161,7 +180,7 @@ void ASEImporter::InternReadFile( const std::string& pFile,
"experience problems"); "experience problems");
} }
// now build the output mesh list. Remove dummies // Now build the output mesh list. Remove dummies
pScene->mNumMeshes = (unsigned int)avOutMeshes.size(); pScene->mNumMeshes = (unsigned int)avOutMeshes.size();
aiMesh** pp = pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; aiMesh** pp = pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
for (std::vector<aiMesh*>::const_iterator for (std::vector<aiMesh*>::const_iterator
@ -173,29 +192,34 @@ void ASEImporter::InternReadFile( const std::string& pFile,
} }
pScene->mNumMeshes = (unsigned int)(pp - pScene->mMeshes); pScene->mNumMeshes = (unsigned int)(pp - pScene->mMeshes);
// build final material indices (remove submaterials and setup // Build final material indices (remove submaterials and setup
// the final list) // the final list)
BuildMaterialIndices(); BuildMaterialIndices();
} }
// *****************************************************************
// Copy all scene graph nodes - lights, cameras, dummies and meshes // Copy all scene graph nodes - lights, cameras, dummies and meshes
// into one large array // into one large array
// *****************************************************************
nodes.reserve(mParser->m_vMeshes.size() +mParser->m_vLights.size() nodes.reserve(mParser->m_vMeshes.size() +mParser->m_vLights.size()
+ mParser->m_vCameras.size() + mParser->m_vDummies.size()); + mParser->m_vCameras.size() + mParser->m_vDummies.size());
// Lights
for (std::vector<ASE::Light>::iterator it = mParser->m_vLights.begin(), for (std::vector<ASE::Light>::iterator it = mParser->m_vLights.begin(),
end = mParser->m_vLights.end();it != end; ++it)nodes.push_back(&(*it)); end = mParser->m_vLights.end();it != end; ++it)nodes.push_back(&(*it));
// Cameras
for (std::vector<ASE::Camera>::iterator it = mParser->m_vCameras.begin(), for (std::vector<ASE::Camera>::iterator it = mParser->m_vCameras.begin(),
end = mParser->m_vCameras.end();it != end; ++it)nodes.push_back(&(*it)); end = mParser->m_vCameras.end();it != end; ++it)nodes.push_back(&(*it));
// Meshes
for (std::vector<ASE::Mesh>::iterator it = mParser->m_vMeshes.begin(), for (std::vector<ASE::Mesh>::iterator it = mParser->m_vMeshes.begin(),
end = mParser->m_vMeshes.end();it != end; ++it)nodes.push_back(&(*it)); end = mParser->m_vMeshes.end();it != end; ++it)nodes.push_back(&(*it));
// Dummies
for (std::vector<ASE::Dummy>::iterator it = mParser->m_vDummies.begin(), for (std::vector<ASE::Dummy>::iterator it = mParser->m_vDummies.begin(),
end = mParser->m_vDummies.end();it != end; ++it)nodes.push_back(&(*it)); end = mParser->m_vDummies.end();it != end; ++it)nodes.push_back(&(*it));
// process target cameras and target lights (
// generate animation channels for them and adjust the node graph)
// ProcessTargets();
// build the final node graph // build the final node graph
BuildNodes(); BuildNodes();
@ -209,8 +233,11 @@ void ASEImporter::InternReadFile( const std::string& pFile,
BuildLights(); BuildLights();
// TODO: STRANGE RESULTS ATM // TODO: STRANGE RESULTS ATM
// *****************************************************************
// If we have no meshes use the SkeletonMeshBuilder helper class // If we have no meshes use the SkeletonMeshBuilder helper class
// to build a mesh for the animation skeleton // to build a mesh for the animation skeleton
// *****************************************************************
if (!pScene->mNumMeshes) if (!pScene->mNumMeshes)
{ {
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
@ -278,7 +305,9 @@ void ASEImporter::BuildAnimations()
// that represent the node transformation. // that represent the node transformation.
if ((*i)->mAnim.akeyPositions.size() > 1 || if ((*i)->mAnim.akeyPositions.size() > 1 ||
(*i)->mAnim.akeyRotations.size() > 1 || (*i)->mAnim.akeyRotations.size() > 1 ||
(*i)->mAnim.akeyScaling.size() > 1) (*i)->mAnim.akeyScaling.size() > 1 ||
(*i)->mTargetAnim.akeyPositions.size() > 1
&& is_not_qnan( (*i)->mTargetPosition.x ))
{ {
++iNum; ++iNum;
} }
@ -298,62 +327,79 @@ void ASEImporter::BuildAnimations()
// Now iterate through all meshes and collect all data we can find // Now iterate through all meshes and collect all data we can find
for (i = nodes.begin();i != nodes.end();++i) for (i = nodes.begin();i != nodes.end();++i)
{ {
if ((*i)->mAnim.akeyPositions.size() > 1 || (*i)->mAnim.akeyRotations.size() > 1) ASE::BaseNode* me = *i;
if ( me->mTargetAnim.akeyPositions.size() > 1
&& is_not_qnan( me->mTargetPosition.x ))
{
// Generate an extra channel for the camera/light target.
// BuildNodes() does also generate an extra node, named
// <baseName>.Target.
aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
nd->mNodeName.Set(me->mName + ".Target");
// Allocate the key array and fill it
nd->mNumPositionKeys = (unsigned int) me->mTargetAnim.akeyPositions.size();
nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
::memcpy(nd->mPositionKeys,&me->mTargetAnim.akeyPositions[0],
nd->mNumPositionKeys * sizeof(aiVectorKey));
}
if (me->mAnim.akeyPositions.size() > 1 || me->mAnim.akeyRotations.size() > 1)
{ {
// Begin a new node animation channel for this node // Begin a new node animation channel for this node
aiNodeAnim* pcNodeAnim = pcAnim->mChannels[iNum++] = new aiNodeAnim(); aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
pcNodeAnim->mNodeName.Set((*i)->mName); nd->mNodeName.Set(me->mName);
// copy position keys // copy position keys
if ((*i)->mAnim.akeyPositions.size() > 1 ) if (me->mAnim.akeyPositions.size() > 1 )
{ {
// Allocate the key array and fill it // Allocate the key array and fill it
pcNodeAnim->mNumPositionKeys = (unsigned int) (*i)->mAnim.akeyPositions.size(); nd->mNumPositionKeys = (unsigned int) me->mAnim.akeyPositions.size();
pcNodeAnim->mPositionKeys = new aiVectorKey[pcNodeAnim->mNumPositionKeys]; nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
::memcpy(pcNodeAnim->mPositionKeys,&(*i)->mAnim.akeyPositions[0], ::memcpy(nd->mPositionKeys,&me->mAnim.akeyPositions[0],
pcNodeAnim->mNumPositionKeys * sizeof(aiVectorKey)); nd->mNumPositionKeys * sizeof(aiVectorKey));
// get the longest node anim channel
for (unsigned int qq = 0; qq < pcNodeAnim->mNumPositionKeys;++qq)
{
pcAnim->mDuration = std::max(pcAnim->mDuration,
pcNodeAnim->mPositionKeys[qq].mTime);
}
} }
// copy rotation keys // copy rotation keys
if ((*i)->mAnim.akeyRotations.size() > 1 ) if (me->mAnim.akeyRotations.size() > 1 )
{ {
// Allocate the key array and fill it // Allocate the key array and fill it
pcNodeAnim->mNumRotationKeys = (unsigned int) (*i)->mAnim.akeyRotations.size(); nd->mNumRotationKeys = (unsigned int) me->mAnim.akeyRotations.size();
pcNodeAnim->mRotationKeys = new aiQuatKey[pcNodeAnim->mNumRotationKeys]; nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
::memcpy(pcNodeAnim->mRotationKeys,&(*i)->mAnim.akeyRotations[0], // **************************************************************
pcNodeAnim->mNumRotationKeys * sizeof(aiQuatKey)); // Rotation keys are offsets to the previous keys.
// We have the quaternion representations of all
// of them, so we just need to concatenate all
// (unit-length) quaternions to get the absolute
// rotations.
// FIX: Rotation keys are ABSOLUTE for the older
// file format 110 (ASC)
// **************************************************************
// get the longest node anim channel aiQuaternion cur;
for (unsigned int qq = 0; qq < pcNodeAnim->mNumRotationKeys;++qq) for (unsigned int a = 0; a < nd->mNumRotationKeys;++a)
{ {
pcAnim->mDuration = std::max(pcAnim->mDuration, aiQuatKey q = me->mAnim.akeyRotations[a];
pcNodeAnim->mRotationKeys[qq].mTime);
if (mParser->iFileFormat > 110)
{
cur = (a ? cur*q.mValue : q.mValue);
q.mValue = cur.Normalize();
}
nd->mRotationKeys[a] = q;
} }
} }
// copy scaling keys // copy scaling keys
if ((*i)->mAnim.akeyScaling.size() > 1 ) if (me->mAnim.akeyScaling.size() > 1 )
{ {
// Allocate the key array and fill it // Allocate the key array and fill it
pcNodeAnim->mNumScalingKeys = (unsigned int) (*i)->mAnim.akeyScaling.size(); nd->mNumScalingKeys = (unsigned int) me->mAnim.akeyScaling.size();
pcNodeAnim->mScalingKeys = new aiVectorKey[pcNodeAnim->mNumScalingKeys]; nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys];
::memcpy(pcNodeAnim->mScalingKeys,&(*i)->mAnim.akeyScaling[0], ::memcpy(nd->mScalingKeys,&me->mAnim.akeyScaling[0],
pcNodeAnim->mNumScalingKeys * sizeof(aiVectorKey)); nd->mNumScalingKeys * sizeof(aiVectorKey));
// get the longest node anim channel
for (unsigned int qq = 0; qq < pcNodeAnim->mNumScalingKeys;++qq)
{
pcAnim->mDuration = std::max(pcAnim->mDuration,
pcNodeAnim->mScalingKeys[qq].mTime);
}
} }
} }
} }
@ -534,15 +580,34 @@ void ASEImporter::AddNodes (std::vector<BaseNode*>& nodes,
mParentAdjust.Inverse(); mParentAdjust.Inverse();
node->mTransformation = mParentAdjust*snode->mTransform; node->mTransformation = mParentAdjust*snode->mTransform;
// Further processing depends on the type of the node
if (snode->mType == ASE::BaseNode::Mesh)
{
// If the type of this node is "Mesh" we need to search // If the type of this node is "Mesh" we need to search
// the list of output meshes in the data structure for // the list of output meshes in the data structure for
// all those that belonged to this node once. This is // all those that belonged to this node once. This is
// slightly inconvinient here and a better solution should // slightly inconvinient here and a better solution should
// be used when this code is refactored next. // be used when this code is refactored next.
if (snode->mType == BaseNode::Mesh)
{
AddMeshes(snode,node); AddMeshes(snode,node);
} }
else if (is_not_qnan( snode->mTargetPosition.x ))
{
// If this is a target camera or light we generate a small
// child node which marks the position of the camera
// target (the direction information is contained in *this*
// node's animation track but the exact target position
// would be lost otherwise)
apcNodes.push_back(new aiNode());
aiNode* node = apcNodes.back();
node->mName.Set ( snode->mName + ".Target" );
node->mTransformation.a4 = snode->mTargetPosition.x;
node->mTransformation.b4 = snode->mTargetPosition.y;
node->mTransformation.c4 = snode->mTargetPosition.z;
node->mParent = pcParent;
}
// add sub nodes // add sub nodes
// aiMatrix4x4 mNewAbs = mat * node->mTransformation; // aiMatrix4x4 mNewAbs = mat * node->mTransformation;

File diff suppressed because it is too large Load Diff

View File

@ -130,11 +130,17 @@ struct Bone
{ {
static int iCnt = 0; static int iCnt = 0;
// Generate a default name for the bone
char szTemp[128]; char szTemp[128];
::sprintf(szTemp,"UNNAMED_%i",iCnt++); ::sprintf(szTemp,"UNNAMED_%i",iCnt++);
mName = szTemp; mName = szTemp;
} }
//! Construction from an existing name
Bone( const std::string& name)
: mName (name)
{}
//! Name of the bone //! Name of the bone
std::string mName; std::string mName;
}; };
@ -224,6 +230,10 @@ struct BaseNode
char szTemp[128]; // should be sufficiently large char szTemp[128]; // should be sufficiently large
::sprintf(szTemp,"UNNAMED_%i",iCnt++); ::sprintf(szTemp,"UNNAMED_%i",iCnt++);
mName = szTemp; mName = szTemp;
// Set mTargetPosition to qnan
const float qnan = std::numeric_limits<float>::quiet_NaN();
mTargetPosition.x = qnan;
} }
//! Name of the mesh //! Name of the mesh
@ -357,7 +367,15 @@ struct Dummy : public BaseNode
} }
}; };
// --------------------------------------------------------------------------------- // Parameters to Parser::Parse()
#define AI_ASE_NEW_FILE_FORMAT 200
#define AI_ASE_OLD_FILE_FORMAT 110
// Internally we're a little bit more tolerant
#define AI_ASE_IS_NEW_FILE_FORMAT() (iFileFormat >= 200)
#define AI_ASE_IS_OLD_FILE_FORMAT() (iFileFormat < 200)
// -------------------------------------------------------------------------------
/** \brief Class to parse ASE files /** \brief Class to parse ASE files
*/ */
class Parser class Parser
@ -369,9 +387,14 @@ private:
public: public:
// -------------------------------------------------------------------
//! Construct a parser from a given input file which is //! Construct a parser from a given input file which is
//! guaranted to be terminated with zero. //! guaranted to be terminated with zero.
Parser (const char* szFile); //! @param szFile Input file
//! @param fileFormatDefault Assumed file format version. If the
//! file format is specified in the file the new value replaces
//! the default value.
Parser (const char* szFile, unsigned int fileFormatDefault);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
//! Parses the file into the parsers internal representation //! Parses the file into the parsers internal representation
@ -384,6 +407,10 @@ private:
//! Parse the *SCENE block in a file //! Parse the *SCENE block in a file
void ParseLV1SceneBlock(); void ParseLV1SceneBlock();
// -------------------------------------------------------------------
//! Parse the *MESH_SOFTSKINVERTS block in a file
void ParseLV1SoftSkinBlock();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
//! Parse the *MATERIAL_LIST block in a file //! Parse the *MATERIAL_LIST block in a file
void ParseLV1MaterialListBlock(); void ParseLV1MaterialListBlock();
@ -593,7 +620,7 @@ private:
public: public:
//! Pointer to current data //! Pointer to current data
const char* m_szFile; const char* filePtr;
//! background color to be passed to the viewer //! background color to be passed to the viewer
//! QNAN if none was found //! QNAN if none was found
@ -635,6 +662,9 @@ public:
//! true if the last character read was an end-line character //! true if the last character read was an end-line character
bool bLastWasEndLine; bool bLastWasEndLine;
//! File format version
unsigned int iFileFormat;
}; };

View File

@ -108,11 +108,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# include "../include/BoostWorkaround/boost/scoped_ptr.hpp" # include "../include/BoostWorkaround/boost/scoped_ptr.hpp"
# include "../include/BoostWorkaround/boost/format.hpp" # include "../include/BoostWorkaround/boost/format.hpp"
# include "../include/BoostWorkaround/boost/common_factor_rt.hpp"
#else #else
# include <boost/scoped_ptr.hpp> # include <boost/scoped_ptr.hpp>
# include <boost/format.hpp> # include <boost/format.hpp>
# include <boost/math/common_factor_rt.hpp>
#endif #endif

View File

@ -177,6 +177,9 @@ protected:
* In fact this means that every vertex that is referenced by * In fact this means that every vertex that is referenced by
* a face is unique. Or the other way round: a vertex index may * a face is unique. Or the other way round: a vertex index may
* not occur twice in a single aiMesh. * not occur twice in a single aiMesh.
* - aiAnimation::mDuration may be -1. Assimp determines the length
* of the animation automatically in this case as the length of
* the longest animation channel.
* *
* If the AI_SCENE_FLAGS_INCOMPLETE-Flag is not set:<br> * If the AI_SCENE_FLAGS_INCOMPLETE-Flag is not set:<br>
* - at least one mesh must be there<br> * - at least one mesh must be there<br>

View File

@ -160,7 +160,7 @@ void FindInvalidDataProcess::Execute( aiScene* pScene)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
template <typename T> template <typename T>
inline const char* ValidateArrayContents(const T* arr, unsigned int size, inline const char* ValidateArrayContents(const T* arr, unsigned int size,
const std::vector<bool>& dirtyMask) const std::vector<bool>& dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true)
{ {
return NULL; return NULL;
} }
@ -168,7 +168,7 @@ inline const char* ValidateArrayContents(const T* arr, unsigned int size,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
template <> template <>
inline const char* ValidateArrayContents<aiVector3D>(const aiVector3D* arr, unsigned int size, inline const char* ValidateArrayContents<aiVector3D>(const aiVector3D* arr, unsigned int size,
const std::vector<bool>& dirtyMask) const std::vector<bool>& dirtyMask, bool mayBeIdentical , bool mayBeZero )
{ {
bool b = false; bool b = false;
for (unsigned int i = 0; i < size;++i) for (unsigned int i = 0; i < size;++i)
@ -180,9 +180,13 @@ inline const char* ValidateArrayContents<aiVector3D>(const aiVector3D* arr, unsi
{ {
return "INF/NAN was found in a vector component"; return "INF/NAN was found in a vector component";
} }
if (!mayBeZero && !v.x && !v.y && !v.z )
{
return "Found zero-length vector";
}
if (i && v != arr[i-1])b = true; if (i && v != arr[i-1])b = true;
} }
if (!b) if (!b && !mayBeIdentical)
return "All vectors are identical"; return "All vectors are identical";
return NULL; return NULL;
} }
@ -190,9 +194,10 @@ inline const char* ValidateArrayContents<aiVector3D>(const aiVector3D* arr, unsi
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
template <typename T> template <typename T>
inline bool ProcessArray(T*& in, unsigned int num,const char* name, inline bool ProcessArray(T*& in, unsigned int num,const char* name,
const std::vector<bool>& dirtyMask) const std::vector<bool>& dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true)
{ {
const char* err = ValidateArrayContents(in,num,dirtyMask); const char* err = ValidateArrayContents(in,num,dirtyMask,
mayBeIdentical,mayBeZero);
if (err) if (err)
{ {
DefaultLogger::get()->error(std::string("FindInvalidDataProcess fails on mesh ") + name + ": " + err); DefaultLogger::get()->error(std::string("FindInvalidDataProcess fails on mesh ") + name + ": " + err);
@ -231,7 +236,7 @@ void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim)
int i = 0; int i = 0;
// ScenePreprocessor's work ... // ScenePreprocessor's work ...
ai_assert(0 != anim->mPositionKeys && 0 != anim->mRotationKeys && 0 != anim->mScalingKeys); ai_assert((0 != anim->mPositionKeys && 0 != anim->mRotationKeys && 0 != anim->mScalingKeys));
// Check whether all values in a tracks are identical - in this case // Check whether all values in a tracks are identical - in this case
// we can remove al keys except one. // we can remove al keys except one.
@ -334,7 +339,7 @@ int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh)
// process mesh normals // process mesh normals
if (pMesh->mNormals && ProcessArray(pMesh->mNormals,pMesh->mNumVertices, if (pMesh->mNormals && ProcessArray(pMesh->mNormals,pMesh->mNumVertices,
"normals",dirtyMask)) "normals",dirtyMask,true,false))
ret = true; ret = true;
// process mesh tangents // process mesh tangents

View File

@ -102,16 +102,445 @@ bool IRRImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
return false; return false;
} }
// ------------------------------------------------------------------------------------------------
void IRRImporter::GetExtensionList(std::string& append)
{
/* NOTE: The file extenxsion .xml is too generic. We'll
* need to open the file in CanRead() and check whether it is
* a real irrlicht file
*/
append.append("*.xml;*.irr");
}
// ------------------------------------------------------------------------------------------------
void IRRImporter::SetupProperties(const Importer* pImp)
{
// read the output frame rate of all node animation channels
fps = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_IRR_ANIM_FPS,100);
if (!fps)
{
DefaultLogger::get()->error("IRR: Invalid FPS configuration");
fps = 100;
}
}
// ------------------------------------------------------------------------------------------------
// Build a mesh tha consists of a single squad (a side of a skybox)
aiMesh* IRRImporter::BuildSingleQuadMesh(const SkyboxVertex& v1,
const SkyboxVertex& v2,
const SkyboxVertex& v3,
const SkyboxVertex& v4)
{
// allocate and prepare the mesh
aiMesh* out = new aiMesh();
out->mPrimitiveTypes = aiPrimitiveType_POLYGON;
out->mNumFaces = 1;
// build the face
out->mFaces = new aiFace[1];
aiFace& face = out->mFaces[0];
face.mNumIndices = 4;
face.mIndices = new unsigned int[4];
for (unsigned int i = 0; i < 4;++i)
face.mIndices[i] = i;
out->mNumVertices = 4;
// copy vertex positions
aiVector3D* vec = out->mVertices = new aiVector3D[4];
*vec++ = v1.position;
*vec++ = v2.position;
*vec++ = v3.position;
*vec = v4.position;
// copy vertex normals
vec = out->mNormals = new aiVector3D[4];
*vec++ = v1.normal;
*vec++ = v2.normal;
*vec++ = v3.normal;
*vec = v4.normal;
// copy texture coordinates
out->mTextureCoords[0] = new aiVector3D[4];
*vec++ = v1.uv;
*vec++ = v2.uv;
*vec++ = v3.uv;
*vec = v4.uv;
return out;
}
// ------------------------------------------------------------------------------------------------
void IRRImporter::BuildSkybox(std::vector<aiMesh*>& meshes, std::vector<aiMaterial*> materials)
{
// Update the material of the skybox - replace the name
// and disable shading for skyboxes.
for (unsigned int i = 0; i < 6;++i)
{
MaterialHelper* out = ( MaterialHelper* ) (*(materials.end()-(6-i)));
aiString s;
s.length = ::sprintf( s.data, "SkyboxSide_%i",i );
out->AddProperty(&s,AI_MATKEY_NAME);
int shading = aiShadingMode_NoShading;
out->AddProperty(&shading,1,AI_MATKEY_SHADING_MODEL);
}
// Skyboxes are much more difficult. They are represented
// by six single planes with different textures, so we'll
// need to build six meshes.
const float l = 10.f; // the size used by Irrlicht
// FRONT SIDE
meshes.push_back( BuildSingleQuadMesh(
SkyboxVertex(-l,-l,-l, 0, 0, 1, 1.f,1.f),
SkyboxVertex( l,-l,-l, 0, 0, 1, 0.f,1.f),
SkyboxVertex( l, l,-l, 0, 0, 1, 0.f,0.f),
SkyboxVertex(-l, l,-l, 0, 0, 1, 1.f,0.f)) );
meshes.back()->mMaterialIndex = materials.size()-6u;
// LEFT SIDE
meshes.push_back( BuildSingleQuadMesh(
SkyboxVertex( l,-l,-l, -1, 0, 0, 1.f,1.f),
SkyboxVertex( l,-l, l, -1, 0, 0, 0.f,1.f),
SkyboxVertex( l, l, l, -1, 0, 0, 0.f,0.f),
SkyboxVertex( l, l,-l, -1, 0, 0, 1.f,0.f)) );
meshes.back()->mMaterialIndex = materials.size()-5u;
// BACK SIDE
meshes.push_back( BuildSingleQuadMesh(
SkyboxVertex( l,-l, l, 0, 0, -1, 1.f,1.f),
SkyboxVertex(-l,-l, l, 0, 0, -1, 0.f,1.f),
SkyboxVertex(-l, l, l, 0, 0, -1, 0.f,0.f),
SkyboxVertex( l, l, l, 0, 0, -1, 1.f,0.f)) );
meshes.back()->mMaterialIndex = materials.size()-4u;
// RIGHT SIDE
meshes.push_back( BuildSingleQuadMesh(
SkyboxVertex(-l,-l, l, 1, 0, 0, 1.f,1.f),
SkyboxVertex(-l,-l,-l, 1, 0, 0, 0.f,1.f),
SkyboxVertex(-l, l,-l, 1, 0, 0, 0.f,0.f),
SkyboxVertex(-l, l, l, 1, 0, 0, 1.f,0.f)) );
meshes.back()->mMaterialIndex = materials.size()-3u;
// TOP SIDE
meshes.push_back( BuildSingleQuadMesh(
SkyboxVertex( l, l,-l, 0, -1, 0, 1.f,1.f),
SkyboxVertex( l, l, l, 0, -1, 0, 0.f,1.f),
SkyboxVertex(-l, l, l, 0, -1, 0, 0.f,0.f),
SkyboxVertex(-l, l,-l, 0, -1, 0, 1.f,0.f)) );
meshes.back()->mMaterialIndex = materials.size()-2u;
// BOTTOM SIDE
meshes.push_back( BuildSingleQuadMesh(
SkyboxVertex( l,-l, l, 0, 1, 0, 0.f,0.f),
SkyboxVertex( l,-l,-l, 0, 1, 0, 1.f,0.f),
SkyboxVertex(-l,-l,-l, 0, 1, 0, 1.f,1.f),
SkyboxVertex(-l,-l,-l, 0, 1, 0, 0.f,1.f)) );
meshes.back()->mMaterialIndex = materials.size()-1u;
}
// ------------------------------------------------------------------------------------------------
void IRRImporter::CopyMaterial(std::vector<aiMaterial*> materials,
std::vector< std::pair<aiMaterial*, unsigned int> >& inmaterials,
unsigned int& defMatIdx,
aiMesh* mesh)
{
if (inmaterials.empty())
{
// Do we have a default material? If not we need to create one
if (0xffffffff == defMatIdx)
{
defMatIdx = (unsigned int)materials.size();
MaterialHelper* mat = new MaterialHelper();
aiString s;
s.Set(AI_DEFAULT_MATERIAL_NAME);
mat->AddProperty(&s,AI_MATKEY_NAME);
aiColor3D c(0.6f,0.6f,0.6f);
mat->AddProperty(&c,1,AI_MATKEY_COLOR_DIFFUSE);
}
mesh->mMaterialIndex = defMatIdx;
return;
}
else if (inmaterials.size() > 1)
{
DefaultLogger::get()->info("IRR: Skipping additional materials");
}
mesh->mMaterialIndex = (unsigned int)materials.size();
materials.push_back(inmaterials[0].first);
}
// ------------------------------------------------------------------------------------------------
inline int ClampSpline(int idx, int size)
{
return ( idx<0 ? size+idx : ( idx>=size ? idx-size : idx ) );
}
// ------------------------------------------------------------------------------------------------
inline void FindSuitableMultiple(int& angle)
{
if (angle < 3)angle = 3;
else if (angle < 10) angle = 10;
else if (angle < 20) angle = 20;
else if (angle < 30) angle = 30;
else
{
}
}
// ------------------------------------------------------------------------------------------------
void IRRImporter::ComputeAnimations(Node* root, std::vector<aiNodeAnim*>& anims,
const aiMatrix4x4& transform)
{
ai_assert(NULL != root);
if (root->animators.empty())return;
typedef std::pair< TemporaryAnim, Animator* > AnimPair;
const unsigned int resolution = 1;
std::vector<AnimPair> temp;
temp.reserve(root->animators.size());
for (std::list<Animator>::iterator it = root->animators.begin();
it != root->animators.end(); ++it)
{
if ((*it).type == Animator::UNKNOWN ||
(*it).type == Animator::OTHER)
{
DefaultLogger::get()->warn("IRR: Skipping unknown or unsupported animator");
continue;
}
temp.push_back(AnimPair(TemporaryAnim(),&(*it)));
}
if (temp.empty())return;
// All animators are applied one after another. We generate a set of
// transformation matrices for each of it. Then we combine all
// transformation matrices, decompose them and build an output animation.
for (std::vector<AnimPair>::iterator it = temp.begin();
it != temp.end(); ++it)
{
TemporaryAnim& out = (*it).first;
Animator* in = (*it).second;
switch (in->type)
{
case Animator::ROTATION:
{
// -----------------------------------------------------
// find out how long a full rotation will take
// This is the least common multiple of 360.f and all
// three euler angles. Although we'll surely find a
// possible multiple (haha) it could be somewhat large
// for our purposes. So we need to modify the angles
// here in order to get good results.
// -----------------------------------------------------
int angles[3];
angles[0] = (int)(in->direction.x*100);
angles[1] = (int)(in->direction.y*100);
angles[2] = (int)(in->direction.z*100);
angles[0] %= 360;
angles[1] %= 360;
angles[2] %= 360;
FindSuitableMultiple(angles[0]);
FindSuitableMultiple(angles[1]);
FindSuitableMultiple(angles[2]);
int lcm = 360;
if (angles[0])
lcm = boost::math::lcm(lcm,angles[0]);
if (angles[1])
lcm = boost::math::lcm(lcm,angles[1]);
if (angles[2])
lcm = boost::math::lcm(lcm,angles[2]);
if (360 == lcm)
break;
// This can be a division through zero, but we don't care
float f1 = (float)lcm / angles[0];
float f2 = (float)lcm / angles[1];
float f3 = (float)lcm / angles[2];
// find out how many time units we'll need for the finest
// track (in seconds) - this defines the number of output
// keys (fps * seconds)
float max ;
if (angles[0])
max = (float)lcm / angles[0];
if (angles[1])
max = std::max(max, (float)lcm / angles[1]);
if (angles[2])
max = std::max(max, (float)lcm / angles[2]);
// Allocate transformation matrices
out.SetupMatrices((unsigned int)(max*fps));
// begin with a zero angle
aiVector3D angle;
for (unsigned int i = 0; i < out.last;++i)
{
// build the rotation matrix for the given euler angles
aiMatrix4x4& m = out.matrices[i];
// we start with the node transformation
m = transform;
aiMatrix4x4 m2;
if (angle.x)
m *= aiMatrix4x4::RotationX(angle.x,m2);
if (angle.y)
m *= aiMatrix4x4::RotationX(angle.y,m2);
if (angle.z)
m *= aiMatrix4x4::RotationZ(angle.z,m2);
// increase the angle
angle += in->direction;
}
// This animation is repeated and repeated ...
out.post = aiAnimBehaviour_REPEAT;
}
break;
case Animator::FLY_CIRCLE:
{
}
break;
case Animator::FLY_STRAIGHT:
{
}
break;
case Animator::FOLLOW_SPLINE:
{
out.post = aiAnimBehaviour_REPEAT;
const int size = (int)in->splineKeys.size();
if (!size)
{
// We have no point in the spline. That's bad. Really bad.
DefaultLogger::get()->warn("IRR: Spline animators with no points defined");
break;
}
else if (size == 1)
{
// We have just one point in the spline
out.SetupMatrices(1);
out.matrices[0].a4 = in->splineKeys[0].mValue.x;
out.matrices[0].b4 = in->splineKeys[0].mValue.y;
out.matrices[0].c4 = in->splineKeys[0].mValue.z;
break;
}
unsigned int ticksPerFull = 15;
out.SetupMatrices(ticksPerFull*fps);
for (unsigned int i = 0; i < out.last;++i)
{
aiMatrix4x4& m = out.matrices[i];
const float dt = (i * in->speed * 0.001f );
const float u = dt - floor(dt);
const int idx = (int)floor(dt) % size;
// get the 4 current points to evaluate the spline
const aiVector3D& p0 = in->splineKeys[ ClampSpline( idx - 1, size ) ].mValue;
const aiVector3D& p1 = in->splineKeys[ ClampSpline( idx + 0, size ) ].mValue;
const aiVector3D& p2 = in->splineKeys[ ClampSpline( idx + 1, size ) ].mValue;
const aiVector3D& p3 = in->splineKeys[ ClampSpline( idx + 2, size ) ].mValue;
// compute polynomials
const float u2 = u*u;
const float u3 = u2*2;
const float h1 = 2.0f * u3 - 3.0f * u2 + 1.0f;
const float h2 = -2.0f * u3 + 3.0f * u3;
const float h3 = u3 - 2.0f * u3;
const float h4 = u3 - u2;
// compute the spline tangents
const aiVector3D t1 = ( p2 - p0 ) * in->tightness;
aiVector3D t2 = ( p3 - p1 ) * in->tightness;
// and use them to get the interpolated point
t2 = (h1 * p1 + p2 * h2 + t1 * h3 + h4 * t2);
// build a simple translation matrix from it
m.a4 = t2.x;
m.b4 = t2.y;
m.c4 = t2.z;
}
}
break;
};
}
aiNodeAnim* out = new aiNodeAnim();
out->mNodeName.Set(root->name);
if (temp.size() == 1)
{
// If there's just one animator to be processed our
// task is quite easy
TemporaryAnim& one = temp[0].first;
out->mPostState = one.post;
out->mNumPositionKeys = one.last;
out->mNumScalingKeys = one.last;
out->mNumRotationKeys = one.last;
out->mPositionKeys = new aiVectorKey[one.last];
out->mScalingKeys = new aiVectorKey[one.last];
out->mRotationKeys = new aiQuatKey[one.last];
for (unsigned int i = 0; i < one.last;++i)
{
aiVectorKey& scaling = out->mScalingKeys[i];
aiVectorKey& position = out->mPositionKeys[i];
aiQuatKey& rotation = out->mRotationKeys[i];
scaling.mTime = position.mTime = rotation.mTime = (double)i;
one.matrices[i].Decompose(scaling.mValue, rotation.mValue, position.mValue);
}
}
// NOTE: It is possible that some of the tracks we're returning
// are dummy tracks, but the ScenePreprocessor will fix that, hopefully
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
BatchLoader& batch, BatchLoader& batch,
std::vector<aiMesh*>& meshes, std::vector<aiMesh*>& meshes,
std::vector<aiNodeAnim*>& anims, std::vector<aiNodeAnim*>& anims,
std::vector<AttachmentInfo>& attach) std::vector<AttachmentInfo>& attach,
std::vector<aiMaterial*> materials,
unsigned int& defMatIdx)
{ {
// Setup the name of this node
rootOut->mName.Set(root->name);
unsigned int oldMeshSize = (unsigned int)meshes.size(); unsigned int oldMeshSize = (unsigned int)meshes.size();
// Now determine the type of the node // Now determine the type of the node
@ -126,7 +555,8 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
aiScene* scene = batch.GetImport(root->meshPath); aiScene* scene = batch.GetImport(root->meshPath);
if (!scene) if (!scene)
{ {
DefaultLogger::get()->error("IRR: Unable to load external file: " + root->meshPath); DefaultLogger::get()->error("IRR: Unable to load external file: "
+ root->meshPath);
break; break;
} }
attach.push_back(AttachmentInfo(scene,rootOut)); attach.push_back(AttachmentInfo(scene,rootOut));
@ -150,8 +580,66 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
std::pair<aiMaterial*, unsigned int>& src = root->materials[i]; std::pair<aiMaterial*, unsigned int>& src = root->materials[i];
scene->mMaterials[i] = src.first; scene->mMaterials[i] = src.first;
}
// Process material flags (e.g. lightmapping) // NOTE: Each mesh should have exactly one material assigned,
// but we do it in a separate loop if this behaviour changes
// in the future.
for (unsigned int i = 0; i < scene->mNumMeshes;++i)
{
// Process material flags
aiMesh* mesh = scene->mMeshes[i];
// If "trans_vertex_alpha" mode is enabled, search all vertex colors
// and check whether they have a common alpha value. This is quite
// often the case so we can simply extract it to a shared oacity
// value.
std::pair<aiMaterial*, unsigned int>& src = root->materials[
mesh->mMaterialIndex];
MaterialHelper* mat = (MaterialHelper*)src.first;
if (mesh->HasVertexColors(0) &&
src.second & AI_IRRMESH_MAT_trans_vertex_alpha)
{
bool bdo = true;
for (unsigned int a = 1; a < mesh->mNumVertices;++a)
{
if (mesh->mColors[0][a].a != mesh->mColors[0][a-1].a)
{
bdo = false;
break;
}
}
if (bdo)
{
DefaultLogger::get()->info("IRR: Replacing mesh vertex "
"alpha with common opacity");
for (unsigned int a = 0; a < mesh->mNumVertices;++a)
mesh->mColors[0][a].a = 1.f;
mat->AddProperty(& mesh->mColors[0][0].a, 1, AI_MATKEY_OPACITY);
}
}
// If we have a second texture coordinate set and a second texture
// (either lightmap, normalmap, 2layered material we need to
// setup the correct UV index for it). The texture can either
// be diffuse (lightmap & 2layer) or a normal map (normal & parallax)
if (mesh->HasTextureCoords(1))
{
int idx = 1;
if (src.second & (AI_IRRMESH_MAT_solid_2layer |
AI_IRRMESH_MAT_lightmap))
{
mat->AddProperty(&idx,1,AI_MATKEY_UVWSRC_DIFFUSE(0));
}
else if (src.second & AI_IRRMESH_MAT_normalmap_solid)
{
mat->AddProperty(&idx,1,AI_MATKEY_UVWSRC_NORMALS(0));
}
}
} }
} }
break; break;
@ -175,38 +663,84 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
else if (mul < 300)mul = 3; else if (mul < 300)mul = 3;
else mul = 4; else mul = 4;
meshes.push_back(StandardShapes::MakeMesh(mul,&StandardShapes::MakeSphere)); meshes.push_back(StandardShapes::MakeMesh(mul,
&StandardShapes::MakeSphere));
// Adjust scaling // Adjust scaling
root->scaling *= root->sphereRadius; root->scaling *= root->sphereRadius;
// Copy one output material
CopyMaterial(materials, root->materials, defMatIdx, meshes.back());
} }
break; break;
case Node::CUBE: case Node::CUBE:
case Node::SKYBOX:
{ {
// Skyboxes and normal cubes - generate the cube first // Generate an unit cube first
meshes.push_back(StandardShapes::MakeMesh(&StandardShapes::MakeHexahedron)); meshes.push_back(StandardShapes::MakeMesh(
&StandardShapes::MakeHexahedron));
// Adjust scaling // Adjust scaling
root->scaling *= root->sphereRadius; root->scaling *= root->sphereRadius;
// Copy one output material
CopyMaterial(materials, root->materials, defMatIdx, meshes.back());
}
break;
case Node::SKYBOX:
{
// A skybox is defined by six materials
if (root->materials.size() < 6)
{
DefaultLogger::get()->error("IRR: There should be six materials "
"for a skybox");
break;
}
// copy those materials and generate 6 meshes for our new skybox
materials.reserve(materials.size() + 6);
for (unsigned int i = 0; i < 6;++i)
materials.insert(materials.end(),root->materials[i].first);
BuildSkybox(meshes,materials);
// *************************************************************
// Skyboxes will require a different code path for rendering,
// so there must be a way for the user to add special support
// for IRR skyboxes. We add a 'IRR.SkyBox_' prefix to the node.
// *************************************************************
root->name = "IRR.SkyBox_" + root->name;
DefaultLogger::get()->info("IRR: Loading skybox, this will "
"require special handling to be displayed correctly");
} }
break; break;
case Node::TERRAIN: case Node::TERRAIN:
{ {
// to support terrains, we'd need to have a texture decoder
DefaultLogger::get()->error("IRR: Unsupported node - TERRAIN");
} }
break; break;
}; };
// Check whether we added a mesh. In this case we'll also // Check whether we added a mesh (or more than one ...). In this case
// need to attach it to the node // we'll also need to attach it to the node
if (oldMeshSize != (unsigned int) meshes.size()) if (oldMeshSize != (unsigned int) meshes.size())
{ {
rootOut->mNumMeshes = 1; rootOut->mNumMeshes = (unsigned int)meshes.size() - oldMeshSize;
rootOut->mMeshes = new unsigned int[1]; rootOut->mMeshes = new unsigned int[rootOut->mNumMeshes];
rootOut->mMeshes[0] = oldMeshSize;
for (unsigned int a = 0; a < rootOut->mNumMeshes;++a)
{
rootOut->mMeshes[a] = oldMeshSize+a;
} }
}
// Setup the name of this node
rootOut->mName.Set(root->name);
// Now compute the final local transformation matrix of the // Now compute the final local transformation matrix of the
// node from the given translation, rotation and scaling values. // node from the given translation, rotation and scaling values.
@ -233,6 +767,9 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
mat.b4 = root->position.y; mat.b4 = root->position.y;
mat.c4 = root->position.z; mat.c4 = root->position.z;
// now compute animations for the node
ComputeAnimations(root,anims,mat);
// Add all children recursively. First allocate enough storage // Add all children recursively. First allocate enough storage
// for them, then call us again // for them, then call us again
rootOut->mNumChildren = (unsigned int)root->children.size(); rootOut->mNumChildren = (unsigned int)root->children.size();
@ -243,7 +780,8 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
{ {
aiNode* node = rootOut->mChildren[i] = new aiNode(); aiNode* node = rootOut->mChildren[i] = new aiNode();
node->mParent = rootOut; node->mParent = rootOut;
GenerateGraph(root->children[i],node,scene,batch,meshes,anims,attach); GenerateGraph(root->children[i],node,scene,batch,meshes,
anims,attach,materials,defMatIdx);
} }
} }
} }
@ -286,7 +824,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
lights.reserve(5); lights.reserve(5);
bool inMaterials = false, inAnimator = false; bool inMaterials = false, inAnimator = false;
unsigned int guessedAnimCnt = 0, guessedMeshCnt = 0; unsigned int guessedAnimCnt = 0, guessedMeshCnt = 0, guessedMatCnt = 0;
// Parse the XML file // Parse the XML file
while (reader->read()) while (reader->read())
@ -297,6 +835,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
if (!ASSIMP_stricmp(reader->getNodeName(),"node")) if (!ASSIMP_stricmp(reader->getNodeName(),"node"))
{ {
// ***********************************************************************
/* What we're going to do with the node depends /* What we're going to do with the node depends
* on its type: * on its type:
* *
@ -310,8 +849,10 @@ void IRRImporter::InternReadFile( const std::string& pFile,
* "empty" - A dummy node * "empty" - A dummy node
* "camera" - A camera * "camera" - A camera
* *
* Each of these nodes can be animated. * Each of these nodes can be animated and all can have multiple
* materials assigned (except lights, cameras and dummies, of course).
*/ */
// ***********************************************************************
const char* sz = reader->getAttributeValueSafe("type"); const char* sz = reader->getAttributeValueSafe("type");
Node* nd; Node* nd;
if (!ASSIMP_stricmp(sz,"mesh")) if (!ASSIMP_stricmp(sz,"mesh"))
@ -398,8 +939,9 @@ void IRRImporter::InternReadFile( const std::string& pFile,
Animator* curAnim = NULL; Animator* curAnim = NULL;
if (inMaterials && curNode->type == Node::ANIMMESH || // FIX: Materials can occur for nearly any type of node
curNode->type == Node::MESH ) if (inMaterials /* && curNode->type == Node::ANIMMESH ||
curNode->type == Node::MESH */)
{ {
/* This is a material description - parse it! /* This is a material description - parse it!
*/ */
@ -407,6 +949,8 @@ void IRRImporter::InternReadFile( const std::string& pFile,
std::pair< aiMaterial*, unsigned int >& p = curNode->materials.back(); std::pair< aiMaterial*, unsigned int >& p = curNode->materials.back();
p.first = ParseMaterial(p.second); p.first = ParseMaterial(p.second);
++guessedMatCnt;
continue; continue;
} }
else if (inAnimator) else if (inAnimator)
@ -467,6 +1011,14 @@ void IRRImporter::InternReadFile( const std::string& pFile,
else if (prop.name == "Direction") else if (prop.name == "Direction")
{ {
curAnim->direction = prop.value; curAnim->direction = prop.value;
// From Irrlicht source - a workaround for backward
// compatibility with Irrlicht 1.1
if (curAnim->direction == aiVector3D())
{
curAnim->direction = aiVector3D(0.f,1.f,0.f);
}
else curAnim->direction.Normalize();
} }
} }
else if (curAnim->type == Animator::FLY_STRAIGHT) else if (curAnim->type == Animator::FLY_STRAIGHT)
@ -782,17 +1334,21 @@ void IRRImporter::InternReadFile( const std::string& pFile,
// temporary data // temporary data
std::vector< aiNodeAnim*> anims; std::vector< aiNodeAnim*> anims;
std::vector< aiMaterial*> materials;
std::vector< AttachmentInfo > attach; std::vector< AttachmentInfo > attach;
std::vector<aiMesh*> meshes; std::vector<aiMesh*> meshes;
// try to guess how much storage we'll need
anims.reserve (guessedAnimCnt + (guessedAnimCnt >> 2)); anims.reserve (guessedAnimCnt + (guessedAnimCnt >> 2));
meshes.reserve (guessedMeshCnt + (guessedMeshCnt >> 2)); meshes.reserve (guessedMeshCnt + (guessedMeshCnt >> 2));
materials.reserve (guessedMatCnt + (guessedMatCnt >> 2));
/* Now process our scenegraph recursively: generate final /* Now process our scenegraph recursively: generate final
* meshes and generate animation channels for all nodes. * meshes and generate animation channels for all nodes.
*/ */
unsigned int defMatIdx = 0xffffffff;
GenerateGraph(root,tempScene->mRootNode, tempScene, GenerateGraph(root,tempScene->mRootNode, tempScene,
batch, meshes, anims, attach); batch, meshes, anims, attach, materials, defMatIdx);
if (!anims.empty()) if (!anims.empty())
{ {

View File

@ -38,8 +38,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file Declaration of the .irrMesh (Irrlight Engine Mesh Format) /** @file Declaration of the .irrMesh (Irrlight Engine Mesh Format)
importer class. */ importer class.
*/
#ifndef AI_IRRLOADER_H_INCLUDED #ifndef AI_IRRLOADER_H_INCLUDED
#define AI_IRRLOADER_H_INCLUDED #define AI_IRRLOADER_H_INCLUDED
@ -78,27 +80,21 @@ public:
protected: protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Called by Importer::GetExtensionList() for each loaded importer. /**
* See BaseImporter::GetExtensionList() for details
*/ */
void GetExtensionList(std::string& append) void GetExtensionList(std::string& append);
{
/* NOTE: The file extenxsion .xml is too generic. We'll
* need to open the file in CanRead() and check whether it is
* a real irrlicht file
*/
append.append("*.xml;*.irr");
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Imports the given file into the given scene structure. /**
* See BaseImporter::InternReadFile() for details
*/ */
void InternReadFile( const std::string& pFile, aiScene* pScene, void InternReadFile( const std::string& pFile, aiScene* pScene,
IOSystem* pIOHandler); IOSystem* pIOHandler);
// -------------------------------------------------------------------
/**
*/
void SetupProperties(const Importer* pImp);
private: private:
/** Data structure for a scenegraph node animator /** Data structure for a scenegraph node animator
@ -170,7 +166,6 @@ private:
Node(ET t) Node(ET t)
: type (t) : type (t)
, scaling (1.f,1.f,1.f) // assume uniform scaling by default , scaling (1.f,1.f,1.f) // assume uniform scaling by default
, animation (NULL)
, framesPerSecond (0.f) , framesPerSecond (0.f)
, sphereRadius (1.f) , sphereRadius (1.f)
, spherePolyCountX (100) , spherePolyCountX (100)
@ -202,9 +197,6 @@ private:
// Parent node // Parent node
Node* parent; Node* parent;
// Animation channels that belongs to this node
aiNodeAnim* animation;
// Animated meshes: frames per second // Animated meshes: frames per second
// 0.f if not specified // 0.f if not specified
float framesPerSecond; float framesPerSecond;
@ -226,14 +218,117 @@ private:
std::list<Animator> animators; std::list<Animator> animators;
}; };
/** Data structure for a vertex in an IRR skybox
*/
struct SkyboxVertex
{
SkyboxVertex()
{}
//! Construction from single vertex components
SkyboxVertex(float px, float py, float pz,
float nx, float ny, float nz,
float uvx, float uvy)
: position (px,py,pz)
, normal (nx,ny,nz)
, uv (uvx,uvy,0.f)
{}
aiVector3D position, normal, uv;
};
/** Temporary data structure to describe an IRR animator
*
* Irrlicht animations always start at the beginning, so
* we don't need "first" and "pre" for the moment.
*/
struct TemporaryAnim
{
TemporaryAnim()
: last (0)
, post (aiAnimBehaviour_DEFAULT)
, matrices (NULL)
{}
~TemporaryAnim()
{
delete[] matrices;
}
void SetupMatrices(unsigned int num)
{
last = num;
matrices = new aiMatrix4x4[num];
}
unsigned int last;
aiAnimBehaviour post;
aiMatrix4x4* matrices;
};
// -------------------------------------------------------------------
/** Fill the scenegraph recursively /** Fill the scenegraph recursively
*/ */
void GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, void GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
BatchLoader& batch, BatchLoader& batch,
std::vector<aiMesh*>& meshes, std::vector<aiMesh*>& meshes,
std::vector<aiNodeAnim*>& anims, std::vector<aiNodeAnim*>& anims,
std::vector<AttachmentInfo>& attach); std::vector<AttachmentInfo>& attach,
std::vector<aiMaterial*> materials,
unsigned int& defaultMatIdx);
// -------------------------------------------------------------------
/** Generate a mesh that consists of just a single quad
*/
aiMesh* BuildSingleQuadMesh(const SkyboxVertex& v1,
const SkyboxVertex& v2,
const SkyboxVertex& v3,
const SkyboxVertex& v4);
// -------------------------------------------------------------------
/** Build a skybox
*
* @param meshes Receives 6 output meshes
* @param materials The last 6 materials are assigned to the newly
* created meshes. The names of the materials are adjusted.
*/
void BuildSkybox(std::vector<aiMesh*>& meshes,
std::vector<aiMaterial*> materials);
// -------------------------------------------------------------------
/** Copy a material for a mesh to the output material list
*
* @param materials Receives an output material
* @param inmaterials List of input materials
* @param defMatIdx Default material index - 0xffffffff if not there
* @param mesh Mesh to work on
*/
void CopyMaterial(std::vector<aiMaterial*> materials,
std::vector< std::pair<aiMaterial*, unsigned int> >& inmaterials,
unsigned int& defMatIdx,
aiMesh* mesh);
// -------------------------------------------------------------------
/** Compute animations for a specific node
*
* @param root Node to be processed
* @param anims The list of output animations
* @param transform Transformation matrix of the current node
* (relative to the parent's coordinate space)
*/
void ComputeAnimations(Node* root, std::vector<aiNodeAnim*>& anims,
const aiMatrix4x4& transform);
private:
unsigned int fps;
}; };

View File

@ -870,20 +870,13 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
DefaultLogger::get()->error("IRRMESH: Not enough indices"); DefaultLogger::get()->error("IRRMESH: Not enough indices");
// Finish processing the mesh - do some small material workarounds // Finish processing the mesh - do some small material workarounds
if (curMatFlags == AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors)
{ {
// Take the opacity value of the current material // Take the opacity value of the current material
// from the common vertex color alpha // from the common vertex color alpha
MaterialHelper* mat = (MaterialHelper*)curMat; MaterialHelper* mat = (MaterialHelper*)curMat;
mat->AddProperty(&curColors[0].a,1,AI_MATKEY_OPACITY); mat->AddProperty(&curColors[0].a,1,AI_MATKEY_OPACITY);
} }
// store the material flags for later use
curMesh->mNumUVComponents[3] = curMatFlags;
if ( curMatFlags & AI_IRRMESH_MAT_lightmap )
{
needLightMap = true;
}
}} }}
break; break;

View File

@ -586,6 +586,7 @@ struct Layer
: mFaceIDXOfs (0) : mFaceIDXOfs (0)
, mPointIDXOfs (0) , mPointIDXOfs (0)
, mParent (0x0) , mParent (0x0)
, skip (false)
{} {}
/** Temporary point list from the file */ /** Temporary point list from the file */
@ -622,6 +623,9 @@ struct Layer
/** Pivot point of the layer */ /** Pivot point of the layer */
aiVector3D mPivot; aiVector3D mPivot;
/** Skip this layer? */
bool skip;
}; };
typedef std::list<LWO::Layer> LayerList; typedef std::list<LWO::Layer> LayerList;

View File

@ -122,20 +122,22 @@ void LWOImporter::InternReadFile( const std::string& pFile,
mFileBuffer = &mBuffer[0] + 12; mFileBuffer = &mBuffer[0] + 12;
fileSize -= 12; fileSize -= 12;
hasNamedLayer = false;
// create temporary storage on the stack but store pointers to it in the class // create temporary storage on the stack but store pointers to it in the class
// instance. Therefore everything will be destructed properly if an exception // instance. Therefore everything will be destructed properly if an exception
// is thrown and we needn't take care of that. // is thrown and we needn't take care of that.
LayerList _mLayers; LayerList _mLayers;
mLayers = &_mLayers;
TagList _mTags;
mTags = &_mTags;
TagMappingTable _mMapping;
mMapping = &_mMapping;
SurfaceList _mSurfaces; SurfaceList _mSurfaces;
TagList _mTags;
TagMappingTable _mMapping;
mLayers = &_mLayers;
mTags = &_mTags;
mMapping = &_mMapping;
mSurfaces = &_mSurfaces; mSurfaces = &_mSurfaces;
// allocate a default layer // Allocate a default layer (layer indices are 1-based from now)
mLayers->push_back(Layer()); mLayers->push_back(Layer());
mCurLayer = &mLayers->back(); mCurLayer = &mLayers->back();
mCurLayer->mName = "<LWODefault>"; mCurLayer->mName = "<LWODefault>";
@ -146,7 +148,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
DefaultLogger::get()->info("LWO file format: LWOB (<= LightWave 5.5)"); DefaultLogger::get()->info("LWO file format: LWOB (<= LightWave 5.5)");
mIsLWO2 = false; mIsLWO2 = false;
this->LoadLWOBFile(); LoadLWOBFile();
} }
// new lightwave format // new lightwave format
@ -155,7 +157,19 @@ void LWOImporter::InternReadFile( const std::string& pFile,
DefaultLogger::get()->info("LWO file format: LWO2 (>= LightWave 6)"); DefaultLogger::get()->info("LWO file format: LWO2 (>= LightWave 6)");
mIsLWO2 = true; mIsLWO2 = true;
this->LoadLWO2File(); LoadLWO2File();
// The newer lightwave format allows the user to configure the
// loader that just one layer is used. If this is the case
// we need to check now whether the requested layer has been found.
if (0xffffffff != configLayerIndex && configLayerIndex > mLayers->size())
throw new ImportErrorException("LWO2: The requested layer was not found");
if (configLayerName.length() && !hasNamedLayer)
{
throw new ImportErrorException("LWO2: Unable to find the requested layer: "
+ configLayerName);
}
} }
// we don't know this format // we don't know this format
@ -179,12 +193,12 @@ void LWOImporter::InternReadFile( const std::string& pFile,
apcNodes. reserve(mLayers->size()); apcNodes. reserve(mLayers->size());
apcMeshes.reserve(mLayers->size()*std::min(((unsigned int)mSurfaces->size()/2u), 1u)); apcMeshes.reserve(mLayers->size()*std::min(((unsigned int)mSurfaces->size()/2u), 1u));
unsigned int iDefaultSurface = 0xffffffff; // index of the default surface unsigned int iDefaultSurface = 0xffffffff; // index of the default surface
for (LayerList::iterator lit = mLayers->begin(), lend = mLayers->end(); for (LayerList::iterator lit = mLayers->begin(), lend = mLayers->end();
lit != lend;++lit) lit != lend;++lit)
{ {
LWO::Layer& layer = *lit; LWO::Layer& layer = *lit;
if (layer.skip)continue;
// I don't know whether there could be dummy layers, but it would be possible // I don't know whether there could be dummy layers, but it would be possible
const unsigned int meshStart = (unsigned int)apcMeshes.size(); const unsigned int meshStart = (unsigned int)apcMeshes.size();
@ -218,15 +232,6 @@ void LWOImporter::InternReadFile( const std::string& pFile,
pSorted[idx].push_back(i); pSorted[idx].push_back(i);
} }
if (0xffffffff == iDefaultSurface)pSorted.erase(pSorted.end()-1); if (0xffffffff == iDefaultSurface)pSorted.erase(pSorted.end()-1);
// now generate output meshes
for (unsigned int p = 0; p < mSurfaces->size();++p)
if (!pSorted[p].empty())pScene->mNumMeshes++;
if (!pScene->mNumMeshes)
throw new ImportErrorException("LWO: There are no meshes");
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
for (unsigned int p = 0,i = 0;i < mSurfaces->size();++i) for (unsigned int p = 0,i = 0;i < mSurfaces->size();++i)
{ {
SortedRep& sorted = pSorted[i]; SortedRep& sorted = pSorted[i];
@ -311,7 +316,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
aiVector3D*& pp = pvUV[w]; aiVector3D*& pp = pvUV[w];
const aiVector2D& src = ((aiVector2D*)&layer.mUVChannels[vUVChannelIndices[w]].rawData[0])[idx]; const aiVector2D& src = ((aiVector2D*)&layer.mUVChannels[vUVChannelIndices[w]].rawData[0])[idx];
pp->x = src.x; pp->x = src.x;
pp->y = src.y; // DX to OGL pp->y = src.y;
pp++; pp++;
} }
@ -338,8 +343,9 @@ void LWOImporter::InternReadFile( const std::string& pFile,
pf++; pf++;
} }
// compute normal vectors for the mesh - we can't use our GenSmoothNormal-Step here // compute normal vectors for the mesh - we can't use our GenSmoothNormal-
// since it wouldn't handle smoothing groups correctly // Step here since it wouldn't handle smoothing groups correctly for LWO.
// So we use a separate implementation.
ComputeNormals(mesh,smoothingGroups,_mSurfaces[i]); ComputeNormals(mesh,smoothingGroups,_mSurfaces[i]);
++p; ++p;
@ -358,6 +364,9 @@ void LWOImporter::InternReadFile( const std::string& pFile,
pcNode->mMeshes[p] = p + meshStart; pcNode->mMeshes[p] = p + meshStart;
} }
if (apcNodes.empty() || apcMeshes.empty())
throw new ImportErrorException("LWO: No meshes loaded");
// the RemoveRedundantMaterials step will clean this up later // the RemoveRedundantMaterials step will clean this up later
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = (unsigned int)mSurfaces->size()]; pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = (unsigned int)mSurfaces->size()];
for (unsigned int mat = 0; mat < pScene->mNumMaterials;++mat) for (unsigned int mat = 0; mat < pScene->mNumMaterials;++mat)
@ -501,6 +510,7 @@ void LWOImporter::ComputeNormals(aiMesh* mesh, const std::vector<unsigned int>&
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void LWOImporter::AddChildren(aiNode* node, uintptr_t parent, std::vector<aiNode*>& apcNodes) void LWOImporter::AddChildren(aiNode* node, uintptr_t parent, std::vector<aiNode*>& apcNodes)
{ {
parent -= 1;
for (uintptr_t i = 0; i < (uintptr_t)apcNodes.size();++i) for (uintptr_t i = 0; i < (uintptr_t)apcNodes.size();++i)
{ {
if (i == parent)continue; if (i == parent)continue;
@ -987,11 +997,15 @@ void LWOImporter::LoadLWO2Clip(unsigned int length)
switch (head->type) switch (head->type)
{ {
case AI_LWO_STIL: case AI_LWO_STIL:
// "Normal" texture
GetS0(clip.path,head->length); GetS0(clip.path,head->length);
clip.type = Clip::STILL; clip.type = Clip::STILL;
break; break;
case AI_LWO_ISEQ: case AI_LWO_ISEQ:
// Image sequence. We'll later take the first.
{ {
uint8_t digits = GetU1(); mFileBuffer++; uint8_t digits = GetU1(); mFileBuffer++;
int16_t offset = GetU2(); mFileBuffer+=4; int16_t offset = GetU2(); mFileBuffer+=4;
@ -999,6 +1013,7 @@ void LWOImporter::LoadLWO2Clip(unsigned int length)
std::string s;std::stringstream ss; std::string s;std::stringstream ss;
GetS0(s,head->length); GetS0(s,head->length);
head->length -= (unsigned int)s.length()+1; head->length -= (unsigned int)s.length()+1;
ss << s; ss << s;
ss << std::setw(digits) << offset + start; ss << std::setw(digits) << offset + start;
@ -1018,6 +1033,8 @@ void LWOImporter::LoadLWO2Clip(unsigned int length)
break; break;
case AI_LWO_XREF: case AI_LWO_XREF:
// Just a cross-reference to another CLIp
clip.type = Clip::REF; clip.type = Clip::REF;
clip.clipRef = GetU4(); clip.clipRef = GetU4();
break; break;
@ -1030,6 +1047,8 @@ void LWOImporter::LoadLWO2Clip(unsigned int length)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2File() void LWOImporter::LoadLWO2File()
{ {
bool skip = false;
LE_NCONST uint8_t* const end = mFileBuffer + fileSize; LE_NCONST uint8_t* const end = mFileBuffer + fileSize;
while (true) while (true)
{ {
@ -1043,6 +1062,7 @@ void LWOImporter::LoadLWO2File()
} }
uint8_t* const next = mFileBuffer+head->length; uint8_t* const next = mFileBuffer+head->length;
unsigned int iUnnamed = 0; unsigned int iUnnamed = 0;
switch (head->type) switch (head->type)
{ {
// new layer // new layer
@ -1053,6 +1073,15 @@ void LWOImporter::LoadLWO2File()
LWO::Layer& layer = mLayers->back(); LWO::Layer& layer = mLayers->back();
mCurLayer = &layer; mCurLayer = &layer;
// load this layer or ignore it? Check the layer index property
// NOTE: The first layer is the default layer, so the layer
// index is one-based now
if (0xffffffff != configLayerIndex && configLayerIndex != mLayers->size())
{
skip = true;
}
else skip = false;
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LAYR,16); AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LAYR,16);
// and parse its properties, e.g. the pivot point // and parse its properties, e.g. the pivot point
@ -1071,6 +1100,13 @@ void LWOImporter::LoadLWO2File()
layer.mName = buffer; layer.mName = buffer;
} }
// load this layer or ignore it? Check the layer name property
if (configLayerName.length() && configLayerName != layer.mName)
{
skip = true;
}
else hasNamedLayer = true;
if (mFileBuffer + 2 <= next) if (mFileBuffer + 2 <= next)
layer.mParent = GetU2(); layer.mParent = GetU2();
@ -1080,6 +1116,8 @@ void LWOImporter::LoadLWO2File()
// vertex list // vertex list
case AI_LWO_PNTS: case AI_LWO_PNTS:
{ {
if (skip)break;
unsigned int old = (unsigned int)mCurLayer->mTempPoints.size(); unsigned int old = (unsigned int)mCurLayer->mTempPoints.size();
LoadLWOPoints(head->length); LoadLWOPoints(head->length);
mCurLayer->mPointIDXOfs = old; mCurLayer->mPointIDXOfs = old;
@ -1095,6 +1133,8 @@ void LWOImporter::LoadLWO2File()
// --- intentionally no break here // --- intentionally no break here
case AI_LWO_VMAP: case AI_LWO_VMAP:
{ {
if (skip)break;
if (mCurLayer->mTempPoints.empty()) if (mCurLayer->mTempPoints.empty())
DefaultLogger::get()->warn("LWO2: Unexpected VMAP chunk"); DefaultLogger::get()->warn("LWO2: Unexpected VMAP chunk");
else LoadLWO2VertexMap(head->length,head->type == AI_LWO_VMAD); else LoadLWO2VertexMap(head->length,head->type == AI_LWO_VMAD);
@ -1103,6 +1143,8 @@ void LWOImporter::LoadLWO2File()
// face list // face list
case AI_LWO_POLS: case AI_LWO_POLS:
{ {
if (skip)break;
unsigned int old = (unsigned int)mCurLayer->mFaces.size(); unsigned int old = (unsigned int)mCurLayer->mFaces.size();
LoadLWO2Polygons(head->length); LoadLWO2Polygons(head->length);
mCurLayer->mFaceIDXOfs = old; mCurLayer->mFaceIDXOfs = old;
@ -1111,6 +1153,8 @@ void LWOImporter::LoadLWO2File()
// polygon tags // polygon tags
case AI_LWO_PTAG: case AI_LWO_PTAG:
{ {
if (skip)break;
if (mCurLayer->mFaces.empty()) if (mCurLayer->mFaces.empty())
DefaultLogger::get()->warn("LWO2: Unexpected PTAG"); DefaultLogger::get()->warn("LWO2: Unexpected PTAG");
else LoadLWO2PolygonTags(head->length); else LoadLWO2PolygonTags(head->length);

View File

@ -386,6 +386,7 @@ protected:
bool configSpeedFlag; bool configSpeedFlag;
unsigned int configLayerIndex; unsigned int configLayerIndex;
std::string configLayerName; std::string configLayerName;
bool hasNamedLayer;
}; };

View File

@ -57,11 +57,12 @@ namespace MDR {
#define AI_MDR_MAGIC_NUMBER_BE MDR_MAKE("RDM5") #define AI_MDR_MAGIC_NUMBER_BE MDR_MAKE("RDM5")
#define AI_MDR_MAGIC_NUMBER_LE MDR_MAKE("5MDR") #define AI_MDR_MAGIC_NUMBER_LE MDR_MAKE("5MDR")
// common limitations // common limitations for MDR - not validated for the moment
#define AI_MDR_VERSION 2 #define AI_MDR_VERSION 2
#define AI_MDR_MAXQPATH 64 #define AI_MDR_MAXQPATH 64
#define AI_MDR_MAX_BONES 128 #define AI_MDR_MAX_BONES 128
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** \brief Data structure for a vertex weight in a MDR file /** \brief Data structure for a vertex weight in a MDR file
*/ */
@ -146,6 +147,9 @@ struct Frame {
aiVector3D localOrigin; // midpoint of bounds, used for sphere cull aiVector3D localOrigin; // midpoint of bounds, used for sphere cull
float radius; // dist from localOrigin to corner float radius; // dist from localOrigin to corner
char name[16]; char name[16];
// bones follow here
} PACK_STRUCT; } PACK_STRUCT;
@ -166,7 +170,6 @@ struct CompFrame
aiVector3D bounds0,bounds1; // bounds of all surfaces of all LOD's for this frame aiVector3D bounds0,bounds1; // bounds of all surfaces of all LOD's for this frame
aiVector3D localOrigin; // midpoint of bounds, used for sphere cull aiVector3D localOrigin; // midpoint of bounds, used for sphere cull
float radius; // dist from localOrigin to corner float radius; // dist from localOrigin to corner
CompBone bones[1]; // [numBones]
} PACK_STRUCT; } PACK_STRUCT;
@ -196,24 +199,24 @@ struct Tag
*/ */
struct Header struct Header
{ {
uint32_t ident; int32_t ident;
uint32_t version; int32_t version;
char name[AI_MDR_MAXQPATH]; char name[AI_MDR_MAXQPATH];
// frames and bones are shared by all levels of detail // frames and bones are shared by all levels of detail
uint32_t numFrames; int32_t numFrames;
uint32_t numBones; int32_t numBones;
uint32_t ofsFrames; int32_t ofsFrames;
// each level of detail has completely separate sets of surfaces // each level of detail has completely separate sets of surfaces
uint32_t numLODs; int32_t numLODs;
uint32_t ofsLODs; int32_t ofsLODs;
uint32_t numTags; int32_t numTags;
uint32_t ofsTags; int32_t ofsTags;
uint32_t ofsEnd; int32_t ofsEnd;
} PACK_STRUCT; } PACK_STRUCT;

View File

@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
using namespace Assimp::MDR; using namespace Assimp::MDR;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
MDRImporter::MDRImporter() MDRImporter::MDRImporter()
@ -76,10 +77,39 @@ bool MDRImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
extension[3] != 'r' && extension[3] != 'R'); extension[3] != 'r' && extension[3] != 'R');
} }
// ------------------------------------------------------------------------------------------------
// Uncompress a matrix
void MDRImporter::MatrixUncompress(aiMatrix4x4& mat,const uint8_t * compressed)
{
int value;
// First decompress the translation part
for (unsigned int n = 0; n < 3;++n)
{
value = (int)((uint16_t *)(compressed))[n];
mat[0][n] = ((float)(value-(1<<15)))/64.f;
}
// Then decompress the rotation matrix
for (unsigned int n = 0, p = 3; n < 3;++n)
{
for (unsigned int m = 0; m < 3;++m,++p)
{
value = (int)((uint16_t *)(compressed))[p];
mat[n][m]=((float)(value-(1<<15)))*(1.0f/(float)((1<<(15))-2));
}
}
// now zero the final row of the matrix
mat[3][0] = mat[3][1] = mat[3][2] = 0.f;
mat[3][3] = 1.f;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Validate the header of the given MDR file // Validate the header of the given MDR file
void MDRImporter::ValidateHeader() void MDRImporter::ValidateHeader()
{ {
// Check the magic word - '5MDR'
if (pcHeader->ident != AI_MDR_MAGIC_NUMBER_BE && if (pcHeader->ident != AI_MDR_MAGIC_NUMBER_BE &&
pcHeader->ident != AI_MDR_MAGIC_NUMBER_LE) pcHeader->ident != AI_MDR_MAGIC_NUMBER_LE)
{ {
@ -94,39 +124,70 @@ void MDRImporter::ValidateHeader()
"magic word found is " + std::string( szBuffer )); "magic word found is " + std::string( szBuffer ));
} }
if (pcHeader->version != AI_MDR_VERSION) // Big endian - swap the fields in the header
DefaultLogger::get()->warn("Unsupported MDR file version (2 (AI_MDR_VERSION) was expected)"); AI_SWAP4(pcHeader->numBones);
AI_SWAP4(pcHeader->numFrames);
AI_SWAP4(pcHeader->ofsFrames);
AI_SWAP4(pcHeader->ofsLODs);
AI_SWAP4(pcHeader->ofsTags);
AI_SWAP4(pcHeader->version);
AI_SWAP4(pcHeader->numTags);
AI_SWAP4(pcHeader->numLODs);
// MDR file version should always be 2
if (pcHeader->version != AI_MDR_VERSION)
DefaultLogger::get()->warn("Unsupported MDR file version (2 was expected)");
// We compute the vertex positions from the bones,
// so we need at least one bone.
if (!pcHeader->numBones) if (!pcHeader->numBones)
DefaultLogger::get()->warn("MDR: At least one bone must be there"); DefaultLogger::get()->warn("MDR: At least one bone must be there");
// validate all LODs // We should have at least the first LOD in the valid range
if (pcHeader->ofsLODs > fileSize) if (pcHeader->ofsLODs > (int)fileSize)
throw new ImportErrorException("MDR: header is invalid - LOD out of range");
// header::ofsFrames is negative if the frames are compressed
if (pcHeader->ofsFrames < 0)
{
// Ugly, but it will be our only change to make further
// reading easier
int32_t* p = const_cast<int32_t*>(&pcHeader->ofsFrames);
*p = -pcHeader->ofsFrames;
compressed = true;
DefaultLogger::get()->info("MDR: Compressed frames");
}
else compressed = false;
// validate all frames // validate all frames
if (pcHeader->ofsFrames + sizeof(MDR::Frame) * (pcHeader->numBones-1) * if ( pcHeader->ofsFrames + sizeof(MDR::Frame) *
sizeof(MDR::Bone) * pcHeader->numFrames > fileSize) (pcHeader->numBones -1) * sizeof(MDR::Bone) *
pcHeader->numFrames > fileSize)
{ {
throw new ImportErrorException("MDR: header is invalid - frame out of range"); throw new ImportErrorException("MDR: header is invalid - frame out of range");
} }
// check whether the requested frame is existing // Check whether the requested frame is existing
if (this->configFrameID >= pcHeader->numFrames) if (configFrameID >= (unsigned int) pcHeader->numFrames)
throw new ImportErrorException("The requested frame is not available"); throw new ImportErrorException("The requested frame is not available");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Validate the header of a given MDR file LOD // Validate the surface header of a given MDR file LOD
void MDRImporter::ValidateLODHeader(BE_NCONST MDR::LOD* pcLOD) void MDRImporter::ValidateLODHeader(BE_NCONST MDR::LOD* pcLOD)
{ {
AI_SWAP4(pcLOD->ofsSurfaces); AI_SWAP4(pcLOD->ofsSurfaces);
AI_SWAP4(pcLOD->numSurfaces); AI_SWAP4(pcLOD->numSurfaces);
AI_SWAP4(pcLOD->ofsEnd); AI_SWAP4(pcLOD->ofsEnd);
const unsigned int iMax = this->fileSize - (unsigned int)((int8_t*)pcLOD-(int8_t*)pcHeader); const unsigned int iMax = fileSize - (unsigned int)((int8_t*)pcLOD-(int8_t*)pcHeader);
// We should have at least one surface here
if (!pcLOD->numSurfaces) if (!pcLOD->numSurfaces)
throw new ImportErrorException("MDR: LOD has zero surfaces assigned"); throw new ImportErrorException("MDR: LOD has zero surfaces assigned");
if (pcLOD->ofsSurfaces > iMax)
throw new ImportErrorException("MDR: LOD header is invalid - surface out of range");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -143,9 +204,10 @@ void MDRImporter::ValidateSurfaceHeader(BE_NCONST MDR::Surface* pcSurf)
AI_SWAP4(pcSurf->ofsVerts); AI_SWAP4(pcSurf->ofsVerts);
AI_SWAP4(pcSurf->shaderIndex); AI_SWAP4(pcSurf->shaderIndex);
const unsigned int iMax = this->fileSize - (unsigned int)((int8_t*)pcSurf-(int8_t*)pcHeader); // Find out how many bytes
const unsigned int iMax = fileSize - (unsigned int)((int8_t*)pcSurf-(int8_t*)pcHeader);
// not exact - there could be extra data in the vertices. // Not exact - there could be extra data in the vertices.
if (pcSurf->ofsTriangles + pcSurf->numTriangles*sizeof(MDR::Triangle) > iMax || if (pcSurf->ofsTriangles + pcSurf->numTriangles*sizeof(MDR::Triangle) > iMax ||
pcSurf->ofsVerts + pcSurf->numVerts*sizeof(MDR::Vertex) > iMax) pcSurf->ofsVerts + pcSurf->numVerts*sizeof(MDR::Vertex) > iMax)
{ {
@ -157,13 +219,14 @@ void MDRImporter::ValidateSurfaceHeader(BE_NCONST MDR::Surface* pcSurf)
// Setup configuration properties // Setup configuration properties
void MDRImporter::SetupProperties(const Importer* pImp) void MDRImporter::SetupProperties(const Importer* pImp)
{ {
// **************************************************************
// The AI_CONFIG_IMPORT_MDR_KEYFRAME option overrides the // The AI_CONFIG_IMPORT_MDR_KEYFRAME option overrides the
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option. // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
if(0xffffffff == (this->configFrameID = pImp->GetPropertyInteger( // **************************************************************
AI_CONFIG_IMPORT_MDR_KEYFRAME,0xffffffff))) configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MDR_KEYFRAME,0xffffffff);
{
this->configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0); if(0xffffffff == configFrameID)
} configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -171,34 +234,36 @@ void MDRImporter::SetupProperties(const Importer* pImp)
void MDRImporter::InternReadFile( const std::string& pFile, void MDRImporter::InternReadFile( const std::string& pFile,
aiScene* pScene, IOSystem* pIOHandler) aiScene* pScene, IOSystem* pIOHandler)
{ {
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile)); boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
// Check whether we can read from the file // Check whether we can read from the file
if( file.get() == NULL) if( file.get() == NULL)
throw new ImportErrorException( "Failed to open MDR file " + pFile + "."); throw new ImportErrorException( "Failed to open MDR file " + pFile + ".");
// check whether the mdr file is large enough to contain the file header // Check whether the mdr file is large enough to contain the file header
fileSize = (unsigned int)file->FileSize(); fileSize = (unsigned int)file->FileSize();
if( fileSize < sizeof(MDR::Header)) if( fileSize < sizeof(MDR::Header))
throw new ImportErrorException( "MDR File is too small."); throw new ImportErrorException( "MDR File is too small.");
// Copy the contents of the file to a buffer
std::vector<unsigned char> mBuffer2(fileSize); std::vector<unsigned char> mBuffer2(fileSize);
file->Read( &mBuffer2[0], 1, fileSize); file->Read( &mBuffer2[0], 1, fileSize);
mBuffer = &mBuffer2[0]; mBuffer = &mBuffer2[0];
// validate the file header and do BigEndian byte swapping for all sub headers // Validate the file header and do BigEndian byte swapping for all sub headers
this->pcHeader = (BE_NCONST MDR::Header*)this->mBuffer; pcHeader = (BE_NCONST MDR::Header*)mBuffer;
this->ValidateHeader(); ValidateHeader();
// go to the first LOD // Go to the first LOD
LE_NCONST MDR::LOD* lod = (LE_NCONST MDR::LOD*)((uint8_t*)this->pcHeader+pcHeader->ofsLODs); LE_NCONST MDR::LOD* lod = (LE_NCONST MDR::LOD*)((uint8_t*)pcHeader+pcHeader->ofsLODs);
std::vector<aiMesh*> outMeshes; std::vector<aiMesh*> outMeshes;
outMeshes.reserve(lod->numSurfaces); outMeshes.reserve(lod->numSurfaces);
// get a pointer to the first surface // Get a pointer to the first surface and continue processing them all
LE_NCONST MDR::Surface* surf = (LE_NCONST MDR::Surface*)((uint8_t*)lod+lod->ofsSurfaces); LE_NCONST MDR::Surface* surf = (LE_NCONST MDR::Surface*)((uint8_t*)lod+lod->ofsSurfaces);
for (uint32_t i = 0; i < lod->numSurfaces; ++i) for (uint32_t i = 0; i < lod->numSurfaces; ++i)
{ {
// The surface must have a) faces b) vertices and c) bone references
if (surf->numTriangles && surf->numVerts && surf->numBoneReferences) if (surf->numTriangles && surf->numVerts && surf->numBoneReferences)
{ {
outMeshes.push_back(new aiMesh()); outMeshes.push_back(new aiMesh());
@ -213,7 +278,7 @@ void MDRImporter::InternReadFile( const std::string& pFile,
mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]; mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
mesh->mBones = new aiBone*[mesh->mNumBones]; mesh->mBones = new aiBone*[mesh->mNumBones];
// allocate output bones // Allocate output bones and generate proper names for them
for (unsigned int p = 0; p < mesh->mNumBones;++p) for (unsigned int p = 0; p < mesh->mNumBones;++p)
{ {
aiBone* bone = mesh->mBones[p] = new aiBone(); aiBone* bone = mesh->mBones[p] = new aiBone();
@ -232,30 +297,40 @@ void MDRImporter::InternReadFile( const std::string& pFile,
// get a pointer to the next vertex // get a pointer to the next vertex
v = (LE_NCONST MDR::Vertex*)((uint8_t*)(v+1) + v->numWeights*sizeof(MDR::Weight)); v = (LE_NCONST MDR::Vertex*)((uint8_t*)(v+1) + v->numWeights*sizeof(MDR::Weight));
// Big Endian - swap the vertex data structure
#ifndef AI_BUILD_BIG_ENDIAN #ifndef AI_BUILD_BIG_ENDIAN
AI_SWAP4(v->numWeights); AI_SWAP4(v->numWeights);
AI_SWAP4(v->normal.x);AI_SWAP4(v->normal.y);AI_SWAP4(v->normal.z); AI_SWAP4(v->normal.x);
AI_SWAP4(v->texCoords.x);AI_SWAP4(v->texCoords.y); AI_SWAP4(v->normal.y);
AI_SWAP4(v->normal.z);
AI_SWAP4(v->texCoords.x);
AI_SWAP4(v->texCoords.y);
#endif #endif
// Fill out output structure
VertexInfo& vert = mVertices[m]; VertexInfo& vert = mVertices[m];
vert.uv.x = v->texCoords.x; vert.uv.y = v->texCoords.y; vert.uv.x = v->texCoords.x; vert.uv.y = v->texCoords.y;
vert.normal = v->normal; vert.normal = v->normal;
vert.start = (unsigned int)mWeights.size(); vert.start = (unsigned int)mWeights.size();
vert.num = v->numWeights; vert.num = v->numWeights;
// Now compute the final vertex position by averaging
// the positions affecting this vertex, weighting by
// the given vertex weights.
for (unsigned int l = 0; l < vert.num; ++l) for (unsigned int l = 0; l < vert.num; ++l)
{ {
} }
} }
// find out how large the output weight buffers must be // Find out how large the output weight buffers must be
LE_NCONST MDR::Triangle* tri = (LE_NCONST MDR::Triangle*)((uint8_t*)surf+surf->ofsTriangles); LE_NCONST MDR::Triangle* tri = (LE_NCONST MDR::Triangle*)((uint8_t*)surf+surf->ofsTriangles);
LE_NCONST MDR::Triangle* const triEnd = tri + surf->numTriangles; LE_NCONST MDR::Triangle* const triEnd = tri + surf->numTriangles;
for (; tri != triEnd; ++tri) for (; tri != triEnd; ++tri)
{ {
for (unsigned int o = 0; o < 3;++o) for (unsigned int o = 0; o < 3;++o)
{ {
// Big endian: swap the 32 Bit index
#ifndef AI_BUILD_BIG_ENDIAN #ifndef AI_BUILD_BIG_ENDIAN
AI_SWAP4(tri->indexes[o]); AI_SWAP4(tri->indexes[o]);
#endif #endif
@ -274,7 +349,7 @@ void MDRImporter::InternReadFile( const std::string& pFile,
} }
} }
// allocate storage for output bone weights // Allocate storage for output bone weights
for (unsigned int p = 0; p < mesh->mNumBones;++p) for (unsigned int p = 0; p < mesh->mNumBones;++p)
{ {
aiBone* bone = mesh->mBones[p]; aiBone* bone = mesh->mBones[p];
@ -285,10 +360,11 @@ void MDRImporter::InternReadFile( const std::string& pFile,
// and build the final output buffers // and build the final output buffers
} }
// get a pointer to the next surface // Get a pointer to the next surface and continue
surf = (LE_NCONST MDR::Surface*)((uint8_t*)surf + surf->ofsEnd); surf = (LE_NCONST MDR::Surface*)((uint8_t*)surf + surf->ofsEnd);
} }
// Copy the vector to the C-style output array
pScene->mNumMeshes = (unsigned int) outMeshes.size(); pScene->mNumMeshes = (unsigned int) outMeshes.size();
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
::memcpy(pScene->mMeshes,&outMeshes[0],sizeof(void*)*pScene->mNumMeshes); ::memcpy(pScene->mMeshes,&outMeshes[0],sizeof(void*)*pScene->mNumMeshes);

View File

@ -117,6 +117,14 @@ protected:
*/ */
void ValidateLODHeader(BE_NCONST MDR::LOD* pcLOD); void ValidateLODHeader(BE_NCONST MDR::LOD* pcLOD);
// -------------------------------------------------------------------
/** Uncompress a matrix
*
* @param mat Destination matrix
* @param compressed Pointer to 24 bytesof compressed data
*/
void MatrixUncompress(aiMatrix4x4& mat,const uint8_t * compressed);
protected: protected:
@ -141,6 +149,9 @@ protected:
/** size of the file, in bytes */ /** size of the file, in bytes */
unsigned int fileSize; unsigned int fileSize;
/** compressed frames? */
bool compressed;
}; };
} // end of namespace Assimp } // end of namespace Assimp

View File

@ -44,6 +44,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef OBJ_TOOLS_H_INC #ifndef OBJ_TOOLS_H_INC
#define OBJ_TOOLS_H_INC #define OBJ_TOOLS_H_INC
#include "fast_atof.h"
namespace Assimp namespace Assimp
{ {

View File

@ -347,7 +347,11 @@ void SMDImporter::CreateOutputMeshes()
for (unsigned int iBone = 0;iBone < face.avVertices[iVert].aiBoneLinks.size();++iBone) for (unsigned int iBone = 0;iBone < face.avVertices[iVert].aiBoneLinks.size();++iBone)
{ {
TempWeightListEntry& pairval = face.avVertices[iVert].aiBoneLinks[iBone]; TempWeightListEntry& pairval = face.avVertices[iVert].aiBoneLinks[iBone];
if (pairval.first >= asBones.size())
// FIX: The second check is here just to make sure we won't
// assign more than one weight to a single vertex index
if (pairval.first >= asBones.size() ||
pairval.first == face.avVertices[iVert].iParentNode)
{ {
DefaultLogger::get()->error("[SMD/VTA] Bone index overflow. " DefaultLogger::get()->error("[SMD/VTA] Bone index overflow. "
"The bone index will be ignored, the weight will be assigned " "The bone index will be ignored, the weight will be assigned "
@ -357,10 +361,16 @@ void SMDImporter::CreateOutputMeshes()
aaiBones[pairval.first].push_back(TempWeightListEntry(iNum,pairval.second)); aaiBones[pairval.first].push_back(TempWeightListEntry(iNum,pairval.second));
fSum += pairval.second; fSum += pairval.second;
} }
// if the sum of all vertex weights is not 1.0 we must assign // ******************************************************************
// If the sum of all vertex weights is not 1.0 we must assign
// the rest to the vertex' parent node. Well, at least the doc says // the rest to the vertex' parent node. Well, at least the doc says
// we should ... // we should ...
if (fSum <= 1.0f) // FIX: We use 0.975 as limit, floating-point inaccuracies seem to
// be very strong in some SMD exporters. Furthermore it is possible
// that the parent of a vertex is 0xffffffff (if the corresponding
// entry in the file was unreadable)
// ******************************************************************
if (fSum < 0.975f && face.avVertices[iVert].iParentNode != 0xffffffff)
{ {
if (face.avVertices[iVert].iParentNode >= asBones.size()) if (face.avVertices[iVert].iParentNode >= asBones.size())
{ {
@ -385,7 +395,6 @@ void SMDImporter::CreateOutputMeshes()
TempWeightListEntry(iNum,1.0f-fSum)); TempWeightListEntry(iNum,1.0f-fSum));
} }
} }
pcMesh->mFaces[iFace].mIndices[iVert] = iNum++; pcMesh->mFaces[iFace].mIndices[iVert] = iNum++;
} }
} }
@ -396,6 +405,8 @@ void SMDImporter::CreateOutputMeshes()
{ {
if (!aaiBones[iBone].empty())++iNum; if (!aaiBones[iBone].empty())++iNum;
} }
if (iNum)
{
pcMesh->mNumBones = iNum; pcMesh->mNumBones = iNum;
pcMesh->mBones = new aiBone*[pcMesh->mNumBones]; pcMesh->mBones = new aiBone*[pcMesh->mNumBones];
iNum = 0; iNum = 0;
@ -418,6 +429,7 @@ void SMDImporter::CreateOutputMeshes()
} }
++iNum; ++iNum;
} }
}
delete[] aaiBones; delete[] aaiBones;
} }
@ -631,11 +643,7 @@ void SMDImporter::CreateOutputMaterials()
pScene->mMaterials[iMat] = pcMat; pScene->mMaterials[iMat] = pcMat;
aiString szName; aiString szName;
#if _MSC_VER >= 1400
szName.length = (size_t)::sprintf_s(szName.data,"Texture_%i",iMat);
#else
szName.length = (size_t)::sprintf(szName.data,"Texture_%i",iMat); szName.length = (size_t)::sprintf(szName.data,"Texture_%i",iMat);
#endif
pcMat->AddProperty(&szName,AI_MATKEY_NAME); pcMat->AddProperty(&szName,AI_MATKEY_NAME);
::strcpy(szName.data, aszTextures[iMat].c_str() ); ::strcpy(szName.data, aszTextures[iMat].c_str() );
@ -1071,6 +1079,11 @@ void SMDImporter::ParseVertex(const char* szCurrent,
const char** szCurrentOut, SMD::Vertex& vertex, const char** szCurrentOut, SMD::Vertex& vertex,
bool bVASection /*= false*/) bool bVASection /*= false*/)
{ {
if (SkipSpaces(&szCurrent) && IsLineEnd(*szCurrent))
{
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
return ParseVertex(szCurrent,szCurrentOut,vertex,bVASection);
}
if(!ParseSignedInt(szCurrent,&szCurrent,(int&)vertex.iParentNode)) if(!ParseSignedInt(szCurrent,&szCurrent,(int&)vertex.iParentNode))
{ {
LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.parent"); LogErrorNoThrow("Unexpected EOF/EOL while parsing vertex.parent");

View File

@ -98,10 +98,41 @@ void ScenePreprocessor::ProcessMesh (aiMesh* mesh)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) void ScenePreprocessor::ProcessAnimation (aiAnimation* anim)
{ {
double first = 10e10, last = -10e10;
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
* compute it now.
*/
if (anim->mDuration == -1.)
{
// Position keys
for (unsigned int i = 0; i < channel->mNumPositionKeys;++i)
{
aiVectorKey& key = channel->mPositionKeys[i];
first = std::min (first, key.mTime);
last = std::max (last, key.mTime);
}
// Scaling keys
for (unsigned int i = 0; i < channel->mNumScalingKeys;++i)
{
aiVectorKey& key = channel->mScalingKeys[i];
first = std::min (first, key.mTime);
last = std::max (last, key.mTime);
}
// Rotation keys
for (unsigned int i = 0; i < channel->mNumRotationKeys;++i)
{
aiQuatKey& key = channel->mRotationKeys[i];
first = std::min (first, key.mTime);
last = std::max (last, key.mTime);
}
}
/* 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
@ -160,4 +191,9 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim)
} }
} }
} }
if (anim->mDuration == -1.)
{
DefaultLogger::get()->debug("Setting animation duration");
anim->mDuration = last - first;
}
} }

View File

@ -56,17 +56,20 @@ SplitLargeMeshesProcess_Triangle::SplitLargeMeshesProcess_Triangle()
{ {
LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES; LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
SplitLargeMeshesProcess_Triangle::~SplitLargeMeshesProcess_Triangle() SplitLargeMeshesProcess_Triangle::~SplitLargeMeshesProcess_Triangle()
{ {
// nothing to do here // nothing to do here
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool SplitLargeMeshesProcess_Triangle::IsActive( unsigned int pFlags) const bool SplitLargeMeshesProcess_Triangle::IsActive( unsigned int pFlags) const
{ {
return (pFlags & aiProcess_SplitLargeMeshes) != 0; return (pFlags & aiProcess_SplitLargeMeshes) != 0;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene) void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene)
@ -96,6 +99,7 @@ void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene)
else DefaultLogger::get()->debug("SplitLargeMeshesProcess_Triangle finished. There was nothing to do"); else DefaultLogger::get()->debug("SplitLargeMeshesProcess_Triangle finished. There was nothing to do");
return; return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Setup properties // Setup properties
void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp) void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp)
@ -103,6 +107,7 @@ void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp)
// get the current value of the split property // get the current value of the split property
this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES); this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Update a node after some meshes have been split // Update a node after some meshes have been split
void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode, void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode,
@ -137,6 +142,7 @@ void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode,
} }
return; return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void SplitLargeMeshesProcess_Triangle::SplitMesh( void SplitLargeMeshesProcess_Triangle::SplitMesh(
@ -339,22 +345,26 @@ void SplitLargeMeshesProcess_Triangle::SplitMesh(
else avList.push_back(std::pair<aiMesh*, unsigned int>(pMesh,a)); else avList.push_back(std::pair<aiMesh*, unsigned int>(pMesh,a));
return; return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
SplitLargeMeshesProcess_Vertex::SplitLargeMeshesProcess_Vertex() SplitLargeMeshesProcess_Vertex::SplitLargeMeshesProcess_Vertex()
{ {
LIMIT = AI_SLM_DEFAULT_MAX_VERTICES; LIMIT = AI_SLM_DEFAULT_MAX_VERTICES;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
SplitLargeMeshesProcess_Vertex::~SplitLargeMeshesProcess_Vertex() SplitLargeMeshesProcess_Vertex::~SplitLargeMeshesProcess_Vertex()
{ {
// nothing to do here // nothing to do here
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool SplitLargeMeshesProcess_Vertex::IsActive( unsigned int pFlags) const bool SplitLargeMeshesProcess_Vertex::IsActive( unsigned int pFlags) const
{ {
return (pFlags & aiProcess_SplitLargeMeshes) != 0; return (pFlags & aiProcess_SplitLargeMeshes) != 0;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene) void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene)
@ -384,12 +394,14 @@ void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene)
else DefaultLogger::get()->debug("SplitLargeMeshesProcess_Vertex finished. There was nothing to do"); else DefaultLogger::get()->debug("SplitLargeMeshesProcess_Vertex finished. There was nothing to do");
return; return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Setup properties // Setup properties
void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp) void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp)
{ {
this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES); this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void SplitLargeMeshesProcess_Vertex::SplitMesh( void SplitLargeMeshesProcess_Vertex::SplitMesh(

View File

@ -0,0 +1,205 @@
/*
Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development 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 Development 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 "AssimpPCH.h"
#include "TargetAnimation.h"
using namespace Assimp;
// ---------------------------------------------------------------------------
KeyIterator::KeyIterator(std::vector<aiVectorKey>* _objPos,
const std::vector<aiVectorKey>* _targetObjPos,
const aiVector3D* defaultObjectPos /*= NULL*/,
const aiVector3D* defaultTargetPos /*= NULL*/)
: reachedEnd (false)
, curTime (-1.)
, objPos(_objPos)
, targetObjPos (_targetObjPos)
, nextObjPos (0)
, nextTargetObjPos(0)
{
// Generate default transformation tracks if necessary
if (!objPos)
{
defaultObjPos.resize(1);
defaultObjPos.front().mTime = 10e10;
if (defaultObjectPos)
defaultObjPos.front().mValue = *defaultObjectPos;
objPos = & defaultObjPos;
}
if (!targetObjPos)
{
defaultTargetObjPos.resize(1);
defaultTargetObjPos.front().mTime = 10e10;
if (defaultTargetPos)
defaultTargetObjPos.front().mValue = *defaultTargetPos;
targetObjPos = & defaultTargetObjPos;
}
}
// ---------------------------------------------------------------------------
void KeyIterator::operator ++()
{
// If we are already at the end of all keyframes, return
if (reachedEnd)return;
int breakThisUglyStuff = 0;
// Now search in all arrays for the time value closest
// to our current position on the time line
double d0,d1;
d0 = objPos->at(nextObjPos).mTime;
if (nextObjPos == objPos->size()-1)
++breakThisUglyStuff;
d1 = targetObjPos->at(nextTargetObjPos).mTime;
if (nextTargetObjPos == targetObjPos->size()-1)
++breakThisUglyStuff;
// Easiest case - all are identical. In this
// case we don't need to interpolate so we can
// return earlier
if ( d0 == d1 )
{
curTime = d0;
curPosition = objPos->at(nextObjPos).mValue;
curTargetPosition = targetObjPos->at(nextTargetObjPos).mValue;
// Increment all counters, regardless whether
// the corresponding arrays are there
++nextObjPos;
++nextTargetObjPos;
}
// An object position key is closest to us
else if (d0 < d1)
{
curTime = d0;
// interpolate the other
if (1 == targetObjPos->size() || !nextTargetObjPos)
{
curTargetPosition = targetObjPos->at(0).mValue;
}
else
{
const aiVectorKey& last = targetObjPos->at(nextTargetObjPos);
const aiVectorKey& first = targetObjPos->at(nextTargetObjPos-1);
/*curTargetPosition = Interpolate(first.mValue, last.mValue,
(curTime-first.mTime) / (last.mTime-first.mTime));*/
}
// increment counters
if (objPos->size() != nextObjPos-1)
++nextObjPos;
if (targetObjPos->size() != nextTargetObjPos-1)
++nextTargetObjPos;
}
// A target position key is closest to us
else
{
curTime = d1;
// interpolate the other
if (1 == objPos->size() || !nextObjPos)
{
curPosition = objPos->at(0).mValue;
}
else
{
const aiVectorKey& last = objPos->at(nextObjPos);
const aiVectorKey& first = objPos->at(nextObjPos-1);
/*curPosition = Interpolate(first.mValue, last.mValue,
(curTime-first.mTime) / (last.mTime-first.mTime));*/
}
}
if (2 == breakThisUglyStuff)
{
// We reached the very last keyframe
reachedEnd = true;
}
}
// ---------------------------------------------------------------------------
void TargetAnimationHelper::SetTargetAnimationChannel (
const std::vector<aiVectorKey>* _targetPositions)
{
ai_assert(NULL != _targetPositions);
targetPositions = _targetPositions;
}
// ---------------------------------------------------------------------------
void TargetAnimationHelper::SetMainAnimationChannel (
std::vector<aiVectorKey>* _objectPositions)
{
ai_assert(NULL != _objectPositions);
objectPositions = _objectPositions;
}
// ---------------------------------------------------------------------------
void TargetAnimationHelper::Process(std::vector<aiVectorKey>* distanceTrack)
{
ai_assert(NULL != objectPositions);
// Iterate through all object keys and interpolate their values if necessary.
// Then get the corresponding target position, compute the difference
// vector between object and target position. Then compute a rotation matrix
// that rotates the base vector of the object coordinate system at that time
// to match the diff vector.
KeyIterator iter(objectPositions,targetPositions);
unsigned int curTarget;
for (;!iter.Finished();++iter)
{
const aiVector3D& position = iter.GetCurPosition();
const aiVector3D& tposition = iter.GetCurTargetPosition();
}
}

View File

@ -0,0 +1,173 @@
/*
Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development 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 Development 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 Defines a helper class for the ASE and 3DS loaders to
help them compute camera and spot light animation channels */
#ifndef AI_TARGET_ANIMATION_H_INC
#define AI_TARGET_ANIMATION_H_INC
namespace Assimp {
// ---------------------------------------------------------------------------
/** Helper class to iterate through all keys in an animation channel.
*
* Missing tracks are interpolated. This is a helper class for
* TargetAnimationHelper, but it can be freely used for other purposes.
*/
class ASSIMP_API KeyIterator
{
public:
// ------------------------------------------------------------------
/** Constructs a new key iterator
*
* @param _objPos Object position track. May be NULL.
* @param _targetObjPos Target object position track. May be NULL.
* @param defaultObjectPos Default object position to be used if
* no animated track is available. May be NULL.
* @param defaultTargetPos Default target position to be used if
* no animated track is available. May be NULL.
*/
KeyIterator(std::vector<aiVectorKey>* _objPos,
const std::vector<aiVectorKey>* _targetObjPos,
const aiVector3D* defaultObjectPos = NULL,
const aiVector3D* defaultTargetPos = NULL);
// ------------------------------------------------------------------
/** Returns true if all keys have been processed
*/
bool Finished() const
{return reachedEnd;}
// ------------------------------------------------------------------
/** Increment the iterator
*/
void operator++();
inline void operator++(int)
{return ++(*this);}
// ------------------------------------------------------------------
/** Getters to retrieve the current state of the iterator
*/
inline const aiVector3D& GetCurPosition() const
{return curPosition;}
inline const aiVector3D& GetCurTargetPosition() const
{return curTargetPosition;}
private:
//! Did we reach the end?
bool reachedEnd;
//! Represents the current position of the iterator
aiVector3D curPosition, curTargetPosition;
double curTime;
//! Input tracks and the next key to process
const std::vector<aiVectorKey>* objPos,*targetObjPos;
unsigned int nextObjPos, nextTargetObjPos;
std::vector<aiVectorKey> defaultObjPos,defaultTargetObjPos;
};
// ---------------------------------------------------------------------------
/** Helper class for the 3DS and ASE loaders to compute camera and spot light
* animations.
*
* 3DS and ASE store the differently to Assimp - there is an animation
* channel for the camera/spot light itself and a separate position
* animation channels specifying the position of the camera/spot light
* look-at target
*/
class ASSIMP_API TargetAnimationHelper
{
public:
TargetAnimationHelper()
: objectPositions (NULL)
{}
// ------------------------------------------------------------------
/** Sets the target animation channel
*
* This channel specifies the position of the camera/spot light
* target at a specific position.
*
* @param targetPositions Translation channel
*/
void SetTargetAnimationChannel (
const std::vector<aiVectorKey>* targetPositions);
// ------------------------------------------------------------------
/** Sets the main animation channel
*
* @param objectPositions Translation channel
*/
void SetMainAnimationChannel (
std::vector<aiVectorKey>* objectPositions);
// ------------------------------------------------------------------
/** Computes final animation channels
*
*/
void Process( std::vector<aiVectorKey>* distanceTrack );
private:
const std::vector<aiVectorKey>* targetPositions;
std::vector<aiVectorKey> *objectPositions;
};
} // ! end namespace Assimp
#endif // include guard

View File

@ -242,6 +242,10 @@ void ValidateDSProcess::Execute( aiScene* pScene)
{ {
ReportError("aiScene::mNumMeshes is 0. At least one mesh must be there"); ReportError("aiScene::mNumMeshes is 0. At least one mesh must be there");
} }
else if (pScene->mMeshes)
{
ReportError("aiScene::mMeshes is non-null although there are no meshes");
}
// validate all animations // validate all animations
if (pScene->mNumAnimations) if (pScene->mNumAnimations)
@ -250,6 +254,10 @@ void ValidateDSProcess::Execute( aiScene* pScene)
DoValidation(pScene->mAnimations,pScene->mNumAnimations, DoValidation(pScene->mAnimations,pScene->mNumAnimations,
"mAnimations","mNumAnimations"); "mAnimations","mNumAnimations");
} }
else if (pScene->mAnimations)
{
ReportError("aiScene::mAnimations is non-null although there are no animations");
}
// validate all cameras // validate all cameras
if (pScene->mNumCameras) if (pScene->mNumCameras)
@ -258,6 +266,10 @@ void ValidateDSProcess::Execute( aiScene* pScene)
DoValidationWithNameCheck(pScene->mCameras,pScene->mNumCameras, DoValidationWithNameCheck(pScene->mCameras,pScene->mNumCameras,
"mCameras","mNumCameras"); "mCameras","mNumCameras");
} }
else if (pScene->mCameras)
{
ReportError("aiScene::mCameras is non-null although there are no cameras");
}
// validate all lights // validate all lights
if (pScene->mNumLights) if (pScene->mNumLights)
@ -266,6 +278,10 @@ void ValidateDSProcess::Execute( aiScene* pScene)
DoValidationWithNameCheck(pScene->mLights,pScene->mNumLights, DoValidationWithNameCheck(pScene->mLights,pScene->mNumLights,
"mLights","mNumLights"); "mLights","mNumLights");
} }
else if (pScene->mLights)
{
ReportError("aiScene::mLights is non-null although there are no lights");
}
// validate all materials // validate all materials
if (pScene->mNumMaterials) if (pScene->mNumMaterials)
@ -277,6 +293,10 @@ void ValidateDSProcess::Execute( aiScene* pScene)
{ {
ReportError("aiScene::mNumMaterials is 0. At least one material must be there"); ReportError("aiScene::mNumMaterials is 0. At least one material must be there");
} }
else if (pScene->mMaterials)
{
ReportError("aiScene::mMaterials is non-null although there are no materials");
}
if (!has)ReportError("The aiScene data structure is empty"); if (!has)ReportError("The aiScene data structure is empty");
DefaultLogger::get()->debug("ValidateDataStructureProcess end"); DefaultLogger::get()->debug("ValidateDataStructureProcess end");
@ -452,7 +472,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
// now validate all bones // now validate all bones
if (pMesh->HasBones()) if (pMesh->mNumBones)
{ {
if (!pMesh->mBones) if (!pMesh->mBones)
{ {
@ -498,6 +518,10 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
} }
delete[] afSum; delete[] afSum;
} }
else if (pMesh->mBones)
{
ReportError("aiMesh::mBones is non-null although there are no bones");
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ValidateDSProcess::Validate( const aiMesh* pMesh, void ValidateDSProcess::Validate( const aiMesh* pMesh,
@ -513,7 +537,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh,
// check whether all vertices affected by this bone are valid // check whether all vertices affected by this bone are valid
for (unsigned int i = 0; i < pBone->mNumWeights;++i) for (unsigned int i = 0; i < pBone->mNumWeights;++i)
{ {
if (pBone->mWeights[i].mVertexId > pMesh->mNumVertices) if (pBone->mWeights[i].mVertexId >= pMesh->mNumVertices)
{ {
this->ReportError("aiBone::mWeights[%i].mVertexId is out of range",i); this->ReportError("aiBone::mWeights[%i].mVertexId is out of range",i);
} }
@ -832,14 +856,14 @@ __break_out:
{ {
if (pNodeAnim->mPositionKeys[i].mTime > pAnimation->mDuration) if (pNodeAnim->mPositionKeys[i].mTime > pAnimation->mDuration)
{ {
this->ReportError("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is larger " ReportError("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is larger "
"than aiAnimation::mDuration (which is %.5f)",i, "than aiAnimation::mDuration (which is %.5f)",i,
(float)pNodeAnim->mPositionKeys[i].mTime, (float)pNodeAnim->mPositionKeys[i].mTime,
(float)pAnimation->mDuration); (float)pAnimation->mDuration);
} }
if (pNodeAnim->mPositionKeys[i].mTime <= dLast) if (pNodeAnim->mPositionKeys[i].mTime <= dLast)
{ {
this->ReportWarning("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is smaller " ReportWarning("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is smaller "
"than aiAnimation::mPositionKeys[%i] (which is %.5f)",i, "than aiAnimation::mPositionKeys[%i] (which is %.5f)",i,
(float)pNodeAnim->mPositionKeys[i].mTime, (float)pNodeAnim->mPositionKeys[i].mTime,
i-1, (float)dLast); i-1, (float)dLast);
@ -860,14 +884,14 @@ __break_out:
{ {
if (pNodeAnim->mRotationKeys[i].mTime > pAnimation->mDuration) if (pNodeAnim->mRotationKeys[i].mTime > pAnimation->mDuration)
{ {
this->ReportError("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is larger " ReportError("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is larger "
"than aiAnimation::mDuration (which is %.5f)",i, "than aiAnimation::mDuration (which is %.5f)",i,
(float)pNodeAnim->mRotationKeys[i].mTime, (float)pNodeAnim->mRotationKeys[i].mTime,
(float)pAnimation->mDuration); (float)pAnimation->mDuration);
} }
if (pNodeAnim->mRotationKeys[i].mTime <= dLast) if (pNodeAnim->mRotationKeys[i].mTime <= dLast)
{ {
this->ReportWarning("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is smaller " ReportWarning("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is smaller "
"than aiAnimation::mRotationKeys[%i] (which is %.5f)",i, "than aiAnimation::mRotationKeys[%i] (which is %.5f)",i,
(float)pNodeAnim->mRotationKeys[i].mTime, (float)pNodeAnim->mRotationKeys[i].mTime,
i-1, (float)dLast); i-1, (float)dLast);
@ -888,14 +912,14 @@ __break_out:
{ {
if (pNodeAnim->mScalingKeys[i].mTime > pAnimation->mDuration) if (pNodeAnim->mScalingKeys[i].mTime > pAnimation->mDuration)
{ {
this->ReportError("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is larger " ReportError("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is larger "
"than aiAnimation::mDuration (which is %.5f)",i, "than aiAnimation::mDuration (which is %.5f)",i,
(float)pNodeAnim->mScalingKeys[i].mTime, (float)pNodeAnim->mScalingKeys[i].mTime,
(float)pAnimation->mDuration); (float)pAnimation->mDuration);
} }
if (pNodeAnim->mScalingKeys[i].mTime <= dLast) if (pNodeAnim->mScalingKeys[i].mTime <= dLast)
{ {
this->ReportWarning("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is smaller " ReportWarning("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is smaller "
"than aiAnimation::mScalingKeys[%i] (which is %.5f)",i, "than aiAnimation::mScalingKeys[%i] (which is %.5f)",i,
(float)pNodeAnim->mScalingKeys[i].mTime, (float)pNodeAnim->mScalingKeys[i].mTime,
i-1, (float)dLast); i-1, (float)dLast);
@ -903,6 +927,12 @@ __break_out:
dLast = pNodeAnim->mScalingKeys[i].mTime; dLast = pNodeAnim->mScalingKeys[i].mTime;
} }
} }
if (!pNodeAnim->mNumScalingKeys && !pNodeAnim->mNumRotationKeys &&
!pNodeAnim->mNumPositionKeys)
{
ReportError("A node animation channel must have at least one subtrack");
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ValidateDSProcess::Validate( const aiNode* pNode) void ValidateDSProcess::Validate( const aiNode* pNode)

View File

@ -73,7 +73,8 @@ SOURCES = AssimpPCH.cpp \
IRRLoader.cpp \ IRRLoader.cpp \
Q3DLoader.cpp \ Q3DLoader.cpp \
ScenePreprocessor.cpp \ ScenePreprocessor.cpp \
B3DImporter.cpp B3DImporter.cpp \
TargetAnimation.cpp
OBJECTS = $(SOURCES:.cpp=.o) OBJECTS = $(SOURCES:.cpp=.o)

View File

@ -73,7 +73,8 @@ SOURCES = AssimpPCH.cpp \
IRRLoader.cpp \ IRRLoader.cpp \
Q3DLoader.cpp \ Q3DLoader.cpp \
ScenePreprocessor.cpp \ ScenePreprocessor.cpp \
B3DImporter.cpp B3DImporter.cpp \
TargetAnimation.cpp
OBJECTS = $(SOURCES:.cpp=.o) OBJECTS = $(SOURCES:.cpp=.o)

View File

@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
extern "C" { extern "C" {
#endif #endif
// ---------------------------------------------------------------------------
/** A time-value pair specifying a certain 3D vector for the given time. */ /** A time-value pair specifying a certain 3D vector for the given time. */
struct aiVectorKey struct aiVectorKey
{ {
@ -77,6 +78,8 @@ struct aiVectorKey
#endif #endif
}; };
// ---------------------------------------------------------------------------
/** A time-value pair specifying a rotation for the given time. For joint /** A time-value pair specifying a rotation for the given time. For joint
* animations the rotation is usually expressed using a quaternion. * animations the rotation is usually expressed using a quaternion.
*/ */
@ -105,34 +108,58 @@ struct aiQuatKey
#endif #endif
}; };
// ---------------------------------------------------------------------------
/** Defines how an animation channel behaves outside the defined time
* range. This corresponds to aiNodeAnim::mPreState and
* aiNodeAnim::mPostState.
*/
enum aiAnimBehaviour enum aiAnimBehaviour
{ {
// --- Wert aus Node-Transformation wird übernommen /** The value from the default node transformation is taken
*/
aiAnimBehaviour_DEFAULT = 0x0, aiAnimBehaviour_DEFAULT = 0x0,
// -- Nächster Key wird verwendet /** The nearest key is used
*/
aiAnimBehaviour_CONSTANT = 0x1, aiAnimBehaviour_CONSTANT = 0x1,
// -- Nächste beiden Keys werden linear extrapoliert /** The value of the nearest two keys is linearly
* extrapolated for the current time value.
*/
aiAnimBehaviour_LINEAR = 0x2, aiAnimBehaviour_LINEAR = 0x2,
// -- Animation wird wiederholt /** The animation is repeated.
// Und das solange bis die Animationszeit (aiAnimation::mDuration) *
// abgelaufen ist. Ist diese 0 läuft das ganze ewig. * If the animation key go from n to m and the current
aiAnimBehaviour_REPEAT = 0x3 * time is t, use the value at (t-n) % (|m-n|).
*/
aiAnimBehaviour_REPEAT = 0x3,
/** This value is not used, it is just here to force the
* the compiler to map this enum to a 32 Bit integer
*/
_aiAnimBehaviour_Force32Bit = 0x8fffffff
}; };
// ---------------------------------------------------------------------------
/** Describes the animation of a single node. The name specifies the /** Describes the animation of a single node. The name specifies the
* bone/node which is affected by this animation channel. The keyframes * bone/node which is affected by this animation channel. The keyframes
* are given in three separate series of values, one each for position, * are given in three separate series of values, one each for position,
* rotation and scaling. The transformation matrix computed from these * rotation and scaling. The transformation matrix computed from these
* values replaces the node's original transformation matrix at a * values replaces the node's original transformation matrix at a
* spefific time. * spefific time. The order in which the transformations are applied is
* - as usual - scaling, rotation, translation.
*
* @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 keys, but they are not forbidden ...
*/ */
struct aiNodeAnim struct aiNodeAnim
{ {
/** The name of the node affected by this animation. The node /** The name of the node affected by this animation. The node
* must exist anf it must be unique. * must exist and it must be unique.
*/ */
C_STRUCT aiString mNodeName; C_STRUCT aiString mNodeName;
@ -172,7 +199,21 @@ struct aiNodeAnim
C_STRUCT aiVectorKey* mScalingKeys; C_STRUCT aiVectorKey* mScalingKeys;
aiAnimBehaviour mPrePostState; /** Defines how the animation behaves before the first
* key is encountered.
*
* The default value is aiAnimBehaviour_DEFAULT (the original
* transformation matrix of the affacted node is taken).
*/
aiAnimBehaviour mPreState;
/** Defines how the animation behaves after the last
* kway was encountered.
*
* The default value is aiAnimBehaviour_DEFAULT (the original
* transformation matrix of the affacted node is taken).
*/
aiAnimBehaviour mPostState;
#ifdef __cplusplus #ifdef __cplusplus
aiNodeAnim() aiNodeAnim()
@ -180,6 +221,8 @@ struct aiNodeAnim
mNumPositionKeys = 0; mPositionKeys = NULL; mNumPositionKeys = 0; mPositionKeys = NULL;
mNumRotationKeys= 0; mRotationKeys = NULL; mNumRotationKeys= 0; mRotationKeys = NULL;
mNumScalingKeys = 0; mScalingKeys = NULL; mNumScalingKeys = 0; mScalingKeys = NULL;
mPreState = mPostState = aiAnimBehaviour_DEFAULT;
} }
~aiNodeAnim() ~aiNodeAnim()
@ -191,6 +234,7 @@ struct aiNodeAnim
#endif // __cplusplus #endif // __cplusplus
}; };
// ---------------------------------------------------------------------------
/** An animation consists of keyframe data for a number of nodes. For /** 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. * each node affected by the animation a separate series of data is given.
*/ */
@ -223,7 +267,7 @@ struct aiAnimation
#ifdef __cplusplus #ifdef __cplusplus
aiAnimation() aiAnimation()
{ {
mDuration = 0; mDuration = -1.;
mTicksPerSecond = 0; mTicksPerSecond = 0;
mNumChannels = 0; mChannels = NULL; mNumChannels = 0; mChannels = NULL;
} }

View File

@ -131,6 +131,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS "imp.ase.reconn" #define AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS "imp.ase.reconn"
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** \brief Configures the LWO loader to load just one layer from the model. /** \brief Configures the LWO loader to load just one layer from the model.
* *
@ -138,11 +139,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* only one of them. This property can be either a string - which specifies * only one of them. This property can be either a string - which specifies
* the name of the layer - or an integer - the index of the layer. If the * the name of the layer - or an integer - the index of the layer. If the
* property is not set the whole LWO model is loaded. Loading fails if the * property is not set the whole LWO model is loaded. Loading fails if the
* requested layer is not available. * requested layer is not available. The layer index is zero-based and the
* layer name may not be empty.
*/ */
#define AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY "imp.lwo.layer" #define AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY "imp.lwo.layer"
// ---------------------------------------------------------------------------
/** \brief Defines the output frame rate of the IRR loader.
*
* IRR animations are difficult to convert for Assimp and there will
* always be a loss of quality. This setting defines how many keys per second
* the converter will compute.<br>
* Property type: integer. Default value: 100
*/
#define AI_CONFIG_IMPORT_IRR_ANIM_FPS "imp.irr.fps"
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** \brief Specifies the maximum angle that may be between two vertex tangents /** \brief Specifies the maximum angle that may be between two vertex tangents
* that their tangents and bitangents are smoothed. * that their tangents and bitangents are smoothed.
@ -253,7 +266,13 @@ enum aiComponent
//! Removes all materials. One default material will //! Removes all materials. One default material will
//! be generated, so aiScene::mNumMaterials will be 1. //! be generated, so aiScene::mNumMaterials will be 1.
//! This makes no real sense without the aiComponent_TEXTURES flag. //! This makes no real sense without the aiComponent_TEXTURES flag.
aiComponent_MATERIALS = 0x800 aiComponent_MATERIALS = 0x800,
/** This value is not used. It is just there to force the
* compiler to map this enum to a 32 Bit integer.
*/
_aiComponent_Force32Bit = 0x9fffffff
}; };
#define aiComponent_COLORSn(n) (1u << (n+20u)) #define aiComponent_COLORSn(n) (1u << (n+20u))

View File

@ -72,7 +72,13 @@ enum aiLightSourceType
//! angle. It has a position and a direction it is pointing to. //! angle. It has a position and a direction it is pointing to.
//! A good example for a spot light is a light spot in //! A good example for a spot light is a light spot in
//! sport arenas. //! sport arenas.
aiLightSource_SPOT = 0x3 aiLightSource_SPOT = 0x3,
/** This value is not used. It is just there to force the
* compiler to map this enum to a 32 Bit integer.
*/
_aiLightSource_Force32Bit = 0x9fffffff
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -76,7 +76,13 @@ enum aiPropertyTypeInfo
/** Simple binary buffer /** Simple binary buffer
*/ */
aiPTI_Buffer = 0x5 aiPTI_Buffer = 0x5,
/** This value is not used. It is just there to force the
* compiler to map this enum to a 32 Bit integer.
*/
_aiPTI_Force32Bit = 0x9fffffff
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -108,7 +114,13 @@ enum aiTextureOp
/** T = T1 + (T2-0.5) /** T = T1 + (T2-0.5)
*/ */
aiTextureOp_SignedAdd = 0x5 aiTextureOp_SignedAdd = 0x5,
/** This value is not used. It is just there to force the
* compiler to map this enum to a 32 Bit integer.
*/
_aiTextureOp_Force32Bit = 0x9fffffff
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -130,7 +142,13 @@ enum aiTextureMapMode
/** A texture coordinate u|v becomes u%1|v%1 if (u-(u%1))%2 is zero and /** A texture coordinate u|v becomes u%1|v%1 if (u-(u%1))%2 is zero and
* 1-(u%1)|1-(v%1) otherwise * 1-(u%1)|1-(v%1) otherwise
*/ */
aiTextureMapMode_Mirror = 0x2 aiTextureMapMode_Mirror = 0x2,
/** This value is not used. It is just there to force the
* compiler to map this enum to a 32 Bit integer.
*/
_aiTextureMapMode_Force32Bit = 0x9fffffff
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -201,7 +219,13 @@ enum aiShadingMode
/** Fresnel shading /** Fresnel shading
*/ */
aiShadingMode_Fresnel = 0xa aiShadingMode_Fresnel = 0xa,
/** This value is not used. It is just there to force the
* compiler to map this enum to a 32 Bit integer.
*/
_aiShadingMode_Force32Bit = 0x9fffffff
}; };

View File

@ -275,7 +275,13 @@ enum aiPrimitiveType
* is provided for your convinience, it splits all polygons in * is provided for your convinience, it splits all polygons in
* triangles (which are much easier to handle). * triangles (which are much easier to handle).
*/ */
aiPrimitiveType_POLYGON = 0x8 aiPrimitiveType_POLYGON = 0x8,
/** This value is not used. It is just there to force the
* compiler to map this enum to a 32 Bit integer.
*/
_aiPrimitiveType_Force32Bit = 0x9fffffff
}; };

View File

@ -79,6 +79,12 @@ struct aiQuaternion
bool operator!= (const aiQuaternion& o) const bool operator!= (const aiQuaternion& o) const
{return !(*this == o);} {return !(*this == o);}
/** Normalize the quaternion */
aiQuaternion& Normalize();
/** Multiply two quaternions */
aiQuaternion operator* (const aiQuaternion& two) const;
/** Performs a spherical interpolation between two quaternions and writes the result into the third. /** Performs a spherical interpolation between two quaternions and writes the result into the third.
* @param pOut Target object to received the interpolated rotation. * @param pOut Target object to received the interpolated rotation.
* @param pStart Start rotation of the interpolation at factor == 0. * @param pStart Start rotation of the interpolation at factor == 0.
@ -248,6 +254,30 @@ inline void aiQuaternion::Interpolate( aiQuaternion& pOut, const aiQuaternion& p
pOut.w = sclp * pStart.w + sclq * end.w; pOut.w = sclp * pStart.w + sclq * end.w;
} }
// ---------------------------------------------------------------------------
inline aiQuaternion& aiQuaternion::Normalize()
{
// compute the magnitude and divide through it
const float mag = x*x+y*y+z*z+w*w;
if (mag)
{
x /= mag;
y /= mag;
z /= mag;
w /= mag;
}
return *this;
}
// ---------------------------------------------------------------------------
inline aiQuaternion aiQuaternion::operator* (const aiQuaternion& t) const
{
return aiQuaternion(w*t.w - x*t.x - y*t.y - z*t.z,
w*t.x + x*t.w + y*t.z - z*t.y,
w*t.y + y*t.w + z*t.x - x*t.z,
w*t.z + z*t.w + x*t.y - y*t.x);
}
} // end extern "C" } // end extern "C"
#endif // __cplusplus #endif // __cplusplus

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,316 @@
*3DSMAX_ASCIIEXPORT 200
*COMMENT "AsciiExport Version 2,00 - Sat Nov 08 17:10:10 2008"
*SCENE {
*SCENE_FILENAME "CameraRollAnim.max"
*SCENE_FIRSTFRAME 0
*SCENE_LASTFRAME 300
*SCENE_FRAMESPEED 30
*SCENE_TICKSPERFRAME 160
*SCENE_BACKGROUND_STATIC 0.0000 0.0000 0.0000
*SCENE_AMBIENT_STATIC 0.0000 0.0000 0.0000
}
*MATERIAL_LIST {
*MATERIAL_COUNT 0
}
*GEOMOBJECT {
*NODE_NAME "Box01"
*NODE_TM {
*NODE_NAME "Box01"
*INHERIT_POS 0 0 0
*INHERIT_ROT 0 0 0
*INHERIT_SCL 0 0 0
*TM_ROW0 1.0000 0.0000 0.0000
*TM_ROW1 0.0000 1.0000 0.0000
*TM_ROW2 0.0000 0.0000 1.0000
*TM_ROW3 10.5413 -0.8547 0.0000
*TM_POS 10.5413 -0.8547 0.0000
*TM_ROTAXIS 0.0000 0.0000 0.0000
*TM_ROTANGLE 0.0000
*TM_SCALE 1.0000 1.0000 1.0000
*TM_SCALEAXIS 0.0000 0.0000 0.0000
*TM_SCALEAXISANG 0.0000
}
*MESH {
*TIMEVALUE 0
*MESH_NUMVERTEX 8
*MESH_NUMFACES 12
*MESH_VERTEX_LIST {
*MESH_VERTEX 0 -24.7863 -24.7863 0.0000
*MESH_VERTEX 1 45.8689 -24.7863 0.0000
*MESH_VERTEX 2 -24.7863 23.0769 0.0000
*MESH_VERTEX 3 45.8689 23.0769 0.0000
*MESH_VERTEX 4 -24.7863 -24.7863 38.7464
*MESH_VERTEX 5 45.8689 -24.7863 38.7464
*MESH_VERTEX 6 -24.7863 23.0769 38.7464
*MESH_VERTEX 7 45.8689 23.0769 38.7464
}
*MESH_FACE_LIST {
*MESH_FACE 0: A: 0 B: 2 C: 3 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 2 *MESH_MTLID 1
*MESH_FACE 1: A: 3 B: 1 C: 0 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 2 *MESH_MTLID 1
*MESH_FACE 2: A: 4 B: 5 C: 7 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 3 *MESH_MTLID 0
*MESH_FACE 3: A: 7 B: 6 C: 4 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 3 *MESH_MTLID 0
*MESH_FACE 4: A: 0 B: 1 C: 5 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 4 *MESH_MTLID 4
*MESH_FACE 5: A: 5 B: 4 C: 0 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 4 *MESH_MTLID 4
*MESH_FACE 6: A: 1 B: 3 C: 7 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 5 *MESH_MTLID 3
*MESH_FACE 7: A: 7 B: 5 C: 1 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 5 *MESH_MTLID 3
*MESH_FACE 8: A: 3 B: 2 C: 6 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 6 *MESH_MTLID 5
*MESH_FACE 9: A: 6 B: 7 C: 3 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 6 *MESH_MTLID 5
*MESH_FACE 10: A: 2 B: 0 C: 4 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 7 *MESH_MTLID 2
*MESH_FACE 11: A: 4 B: 6 C: 2 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 7 *MESH_MTLID 2
}
*MESH_NUMTVERTEX 12
*MESH_TVERTLIST {
*MESH_TVERT 0 0.0000 0.0000 0.0000
*MESH_TVERT 1 1.0000 0.0000 0.0000
*MESH_TVERT 2 0.0000 1.0000 0.0000
*MESH_TVERT 3 1.0000 1.0000 0.0000
*MESH_TVERT 4 0.0000 0.0000 0.0000
*MESH_TVERT 5 1.0000 0.0000 0.0000
*MESH_TVERT 6 0.0000 1.0000 0.0000
*MESH_TVERT 7 1.0000 1.0000 0.0000
*MESH_TVERT 8 0.0000 0.0000 0.0000
*MESH_TVERT 9 1.0000 0.0000 0.0000
*MESH_TVERT 10 0.0000 1.0000 0.0000
*MESH_TVERT 11 1.0000 1.0000 0.0000
}
*MESH_NUMTVFACES 12
*MESH_TFACELIST {
*MESH_TFACE 0 9 11 10
*MESH_TFACE 1 10 8 9
*MESH_TFACE 2 8 9 11
*MESH_TFACE 3 11 10 8
*MESH_TFACE 4 4 5 7
*MESH_TFACE 5 7 6 4
*MESH_TFACE 6 0 1 3
*MESH_TFACE 7 3 2 0
*MESH_TFACE 8 4 5 7
*MESH_TFACE 9 7 6 4
*MESH_TFACE 10 0 1 3
*MESH_TFACE 11 3 2 0
}
*MESH_NUMCVERTEX 0
*MESH_NORMALS {
*MESH_FACENORMAL 0 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 0 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 2 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 3 0.0000 0.0000 -1.0000
*MESH_FACENORMAL 1 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 3 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 1 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 0 0.0000 0.0000 -1.0000
*MESH_FACENORMAL 2 0.0000 -0.0000 1.0000
*MESH_VERTEXNORMAL 4 0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 5 0.0000 -0.0000 1.0000
*MESH_VERTEXNORMAL 7 0.0000 0.0000 1.0000
*MESH_FACENORMAL 3 -0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 7 0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 6 -0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 4 0.0000 0.0000 1.0000
*MESH_FACENORMAL 4 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 0 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 1 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 5 0.0000 -1.0000 0.0000
*MESH_FACENORMAL 5 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 5 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 4 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 0 0.0000 -1.0000 0.0000
*MESH_FACENORMAL 6 1.0000 0.0000 -0.0000
*MESH_VERTEXNORMAL 1 1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 3 1.0000 0.0000 -0.0000
*MESH_VERTEXNORMAL 7 1.0000 0.0000 0.0000
*MESH_FACENORMAL 7 1.0000 -0.0000 0.0000
*MESH_VERTEXNORMAL 7 1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 5 1.0000 -0.0000 0.0000
*MESH_VERTEXNORMAL 1 1.0000 0.0000 0.0000
*MESH_FACENORMAL 8 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 3 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 2 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 6 0.0000 1.0000 0.0000
*MESH_FACENORMAL 9 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 6 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 7 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 3 0.0000 1.0000 0.0000
*MESH_FACENORMAL 10 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 2 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 0 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 4 -1.0000 0.0000 0.0000
*MESH_FACENORMAL 11 -1.0000 -0.0000 -0.0000
*MESH_VERTEXNORMAL 4 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 6 -1.0000 -0.0000 -0.0000
*MESH_VERTEXNORMAL 2 -1.0000 0.0000 0.0000
}
}
*PROP_MOTIONBLUR 0
*PROP_CASTSHADOW 1
*PROP_RECVSHADOW 1
*WIREFRAME_COLOR 0.6941 0.3451 0.1059
}
*CAMERAOBJECT {
*NODE_NAME "Camera01"
*CAMERA_TYPE Target
*NODE_TM {
*NODE_NAME "Camera01"
*INHERIT_POS 0 0 0
*INHERIT_ROT 0 0 0
*INHERIT_SCL 1 1 1
*TM_ROW0 -0.0301 -0.9995 0.0009
*TM_ROW1 0.0000 0.0009 1.0000
*TM_ROW2 -0.9995 0.0301 0.0000
*TM_ROW3 -153.0771 3.2720 22.7776
*TM_POS -153.0771 3.2720 22.7776
*TM_ROTAXIS 0.5656 -0.5834 -0.5829
*TM_ROTANGLE 4.1718
*TM_SCALE 1.0000 1.0000 1.0000
*TM_SCALEAXIS 0.0000 0.0000 0.0000
*TM_SCALEAXISANG 0.0000
}
*NODE_TM {
*NODE_NAME "Camera01.Target"
*INHERIT_POS 0 0 0
*INHERIT_ROT 0 0 0
*INHERIT_SCL 0 0 0
*TM_ROW0 1.0000 0.0000 0.0000
*TM_ROW1 0.0000 1.0000 0.0000
*TM_ROW2 0.0000 0.0000 1.0000
*TM_ROW3 -37.2279 -0.2205 22.7776
*TM_POS -37.2279 -0.2205 22.7776
*TM_ROTAXIS 0.0000 0.0000 0.0000
*TM_ROTANGLE 0.0000
*TM_SCALE 1.0000 1.0000 1.0000
*TM_SCALEAXIS 0.0000 0.0000 0.0000
*TM_SCALEAXISANG 0.0000
}
*CAMERA_SETTINGS {
*TIMEVALUE 0
*CAMERA_NEAR 0.0000
*CAMERA_FAR 1000.0000
*CAMERA_FOV 0.7854
*CAMERA_TDIST 115.9018
}
*TM_ANIMATION {
*NODE_NAME "Camera01"
*CONTROL_ROT_TRACK {
*CONTROL_ROT_SAMPLE 0 0.5656 -0.5834 -0.5829 4.1718
*CONTROL_ROT_SAMPLE 160 0.9996 -0.0300 -0.0001 0.0003
*CONTROL_ROT_SAMPLE 320 0.9995 -0.0302 -0.0001 0.0008
*CONTROL_ROT_SAMPLE 480 0.9995 -0.0301 -0.0001 0.0014
*CONTROL_ROT_SAMPLE 640 0.9995 -0.0301 0.0000 0.0019
*CONTROL_ROT_SAMPLE 800 0.9995 -0.0301 -0.0000 0.0024
*CONTROL_ROT_SAMPLE 960 0.9995 -0.0301 0.0000 0.0029
*CONTROL_ROT_SAMPLE 1120 0.9995 -0.0301 -0.0000 0.0035
*CONTROL_ROT_SAMPLE 1280 0.9995 -0.0301 -0.0000 0.0039
*CONTROL_ROT_SAMPLE 1440 0.9995 -0.0301 -0.0000 0.0044
*CONTROL_ROT_SAMPLE 1600 0.9995 -0.0301 0.0000 0.0049
*CONTROL_ROT_SAMPLE 1760 -0.9995 0.0301 0.0000 6.2778
*CONTROL_ROT_SAMPLE 1920 0.9995 -0.0302 -0.0000 0.0058
*CONTROL_ROT_SAMPLE 2080 0.9995 -0.0301 0.0000 0.0063
*CONTROL_ROT_SAMPLE 2240 0.9995 -0.0301 0.0000 0.0067
*CONTROL_ROT_SAMPLE 2400 0.9995 -0.0301 -0.0000 0.0072
*CONTROL_ROT_SAMPLE 2560 0.9995 -0.0301 0.0000 0.0076
*CONTROL_ROT_SAMPLE 2720 0.9995 -0.0301 0.0000 0.0080
*CONTROL_ROT_SAMPLE 2880 0.9995 -0.0301 0.0000 0.0084
*CONTROL_ROT_SAMPLE 3040 0.9995 -0.0301 -0.0000 0.0088
*CONTROL_ROT_SAMPLE 3200 0.9995 -0.0301 0.0000 0.0092
*CONTROL_ROT_SAMPLE 3360 0.9995 -0.0301 -0.0000 0.0095
*CONTROL_ROT_SAMPLE 3520 0.9995 -0.0301 0.0000 0.0099
*CONTROL_ROT_SAMPLE 3680 0.9995 -0.0301 0.0000 0.0103
*CONTROL_ROT_SAMPLE 3840 0.9995 -0.0301 -0.0000 0.0106
*CONTROL_ROT_SAMPLE 4000 0.9995 -0.0301 -0.0000 0.0110
*CONTROL_ROT_SAMPLE 4160 0.9995 -0.0301 0.0000 0.0113
*CONTROL_ROT_SAMPLE 4320 0.9995 -0.0301 0.0000 0.0116
*CONTROL_ROT_SAMPLE 4480 0.9995 -0.0301 0.0000 0.0119
*CONTROL_ROT_SAMPLE 4640 0.9995 -0.0301 -0.0000 0.0122
*CONTROL_ROT_SAMPLE 4800 0.9995 -0.0301 0.0000 0.0125
*CONTROL_ROT_SAMPLE 4960 0.9995 -0.0301 0.0000 0.0128
*CONTROL_ROT_SAMPLE 5120 0.9995 -0.0301 0.0000 0.0131
*CONTROL_ROT_SAMPLE 5280 0.9995 -0.0301 -0.0000 0.0133
*CONTROL_ROT_SAMPLE 5440 0.9995 -0.0301 0.0000 0.0136
*CONTROL_ROT_SAMPLE 5600 0.9995 -0.0301 -0.0000 0.0138
*CONTROL_ROT_SAMPLE 5760 0.9995 -0.0301 0.0000 0.0140
*CONTROL_ROT_SAMPLE 5920 0.9995 -0.0301 -0.0000 0.0143
*CONTROL_ROT_SAMPLE 6080 0.9995 -0.0301 0.0000 0.0145
*CONTROL_ROT_SAMPLE 6240 0.9995 -0.0301 0.0000 0.0147
*CONTROL_ROT_SAMPLE 6400 0.9995 -0.0301 -0.0000 0.0149
*CONTROL_ROT_SAMPLE 6560 0.9995 -0.0301 0.0000 0.0151
*CONTROL_ROT_SAMPLE 6720 0.9995 -0.0301 0.0000 0.0153
*CONTROL_ROT_SAMPLE 6880 0.9995 -0.0301 -0.0000 0.0154
*CONTROL_ROT_SAMPLE 7040 0.9995 -0.0301 -0.0000 0.0156
*CONTROL_ROT_SAMPLE 7200 0.9995 -0.0301 0.0000 0.0157
*CONTROL_ROT_SAMPLE 7360 0.9995 -0.0301 -0.0000 0.0159
*CONTROL_ROT_SAMPLE 7520 0.9995 -0.0301 0.0000 0.0160
*CONTROL_ROT_SAMPLE 7680 0.9995 -0.0301 -0.0000 0.0161
*CONTROL_ROT_SAMPLE 7840 0.9995 -0.0301 0.0000 0.0162
*CONTROL_ROT_SAMPLE 8000 0.9995 -0.0301 -0.0000 0.0163
*CONTROL_ROT_SAMPLE 8160 0.9995 -0.0301 -0.0000 0.0164
*CONTROL_ROT_SAMPLE 8320 0.9995 -0.0301 0.0000 0.0165
*CONTROL_ROT_SAMPLE 8480 0.9995 -0.0301 -0.0000 0.0166
*CONTROL_ROT_SAMPLE 8640 0.9995 -0.0301 0.0000 0.0167
*CONTROL_ROT_SAMPLE 8800 0.9995 -0.0301 -0.0000 0.0167
*CONTROL_ROT_SAMPLE 8960 0.9995 -0.0301 0.0000 0.0168
*CONTROL_ROT_SAMPLE 9120 0.9995 -0.0301 0.0000 0.0168
*CONTROL_ROT_SAMPLE 9280 0.9995 -0.0301 0.0000 0.0168
*CONTROL_ROT_SAMPLE 9440 0.9995 -0.0301 0.0000 0.0168
*CONTROL_ROT_SAMPLE 9600 0.9995 -0.0301 0.0000 0.0169
*CONTROL_ROT_SAMPLE 9760 0.9995 -0.0301 -0.0000 0.0169
*CONTROL_ROT_SAMPLE 9920 0.9995 -0.0301 -0.0000 0.0168
*CONTROL_ROT_SAMPLE 10080 0.9995 -0.0301 0.0000 0.0168
*CONTROL_ROT_SAMPLE 10240 0.9995 -0.0301 -0.0000 0.0168
*CONTROL_ROT_SAMPLE 10400 0.9995 -0.0301 -0.0000 0.0168
*CONTROL_ROT_SAMPLE 10560 0.9995 -0.0301 0.0000 0.0167
*CONTROL_ROT_SAMPLE 10720 0.9995 -0.0301 0.0000 0.0167
*CONTROL_ROT_SAMPLE 10880 0.9995 -0.0301 0.0000 0.0166
*CONTROL_ROT_SAMPLE 11040 0.9995 -0.0301 0.0000 0.0165
*CONTROL_ROT_SAMPLE 11200 0.9995 -0.0301 -0.0000 0.0164
*CONTROL_ROT_SAMPLE 11360 0.9995 -0.0301 0.0000 0.0163
*CONTROL_ROT_SAMPLE 11520 0.9995 -0.0301 -0.0000 0.0162
*CONTROL_ROT_SAMPLE 11680 0.9995 -0.0301 0.0000 0.0161
*CONTROL_ROT_SAMPLE 11840 0.9995 -0.0301 -0.0000 0.0160
*CONTROL_ROT_SAMPLE 12000 0.9995 -0.0301 -0.0000 0.0159
*CONTROL_ROT_SAMPLE 12160 0.9995 -0.0301 0.0000 0.0157
*CONTROL_ROT_SAMPLE 12320 0.9995 -0.0301 0.0000 0.0156
*CONTROL_ROT_SAMPLE 12480 0.9995 -0.0301 0.0000 0.0154
*CONTROL_ROT_SAMPLE 12640 0.9995 -0.0301 0.0000 0.0153
*CONTROL_ROT_SAMPLE 12800 0.9995 -0.0301 0.0000 0.0151
*CONTROL_ROT_SAMPLE 12960 0.9995 -0.0301 0.0000 0.0149
*CONTROL_ROT_SAMPLE 13120 0.9995 -0.0301 0.0000 0.0147
*CONTROL_ROT_SAMPLE 13280 0.9995 -0.0301 0.0000 0.0145
*CONTROL_ROT_SAMPLE 13440 0.9995 -0.0301 -0.0000 0.0143
*CONTROL_ROT_SAMPLE 13600 0.9995 -0.0301 -0.0000 0.0140
*CONTROL_ROT_SAMPLE 13760 0.9995 -0.0301 0.0000 0.0138
*CONTROL_ROT_SAMPLE 13920 0.9995 -0.0301 0.0000 0.0136
*CONTROL_ROT_SAMPLE 14080 0.9995 -0.0301 -0.0000 0.0133
*CONTROL_ROT_SAMPLE 14240 0.9995 -0.0301 0.0000 0.0131
*CONTROL_ROT_SAMPLE 14400 0.9995 -0.0301 0.0000 0.0128
*CONTROL_ROT_SAMPLE 14560 0.9995 -0.0301 0.0000 0.0125
*CONTROL_ROT_SAMPLE 14720 0.9995 -0.0301 0.0000 0.0122
*CONTROL_ROT_SAMPLE 14880 0.9995 -0.0301 -0.0000 0.0119
*CONTROL_ROT_SAMPLE 15040 0.9995 -0.0301 0.0000 0.0116
*CONTROL_ROT_SAMPLE 15200 0.9995 -0.0301 0.0000 0.0113
*CONTROL_ROT_SAMPLE 15360 0.9995 -0.0301 0.0000 0.0110
*CONTROL_ROT_SAMPLE 15520 0.9995 -0.0301 0.0000 0.0106
*CONTROL_ROT_SAMPLE 15680 0.9995 -0.0301 0.0000 0.0103
*CONTROL_ROT_SAMPLE 15840 0.9995 -0.0301 0.0000 0.0099
*CONTROL_ROT_SAMPLE 16000 0.9995 -0.0301 0.0000 0.0095
*CONTROL_ROT_SAMPLE 16160 0.9995 -0.0301 0.0000 0.0092
*CONTROL_ROT_SAMPLE 16320 0.9995 -0.0301 -0.0000 0.0088
*CONTROL_ROT_SAMPLE 16480 0.9995 -0.0301 0.0000 0.0084
*CONTROL_ROT_SAMPLE 16640 0.9995 -0.0301 0.0000 0.0080
*CONTROL_ROT_SAMPLE 16800 0.9995 -0.0301 0.0000 0.0076
*CONTROL_ROT_SAMPLE 16960 0.9995 -0.0301 -0.0000 0.0072
*CONTROL_ROT_SAMPLE 17120 0.9995 -0.0301 0.0000 0.0067
*CONTROL_ROT_SAMPLE 17280 0.9995 -0.0301 0.0000 0.0063
*CONTROL_ROT_SAMPLE 17440 0.9995 -0.0301 -0.0000 0.0058
*CONTROL_ROT_SAMPLE 17600 0.9995 -0.0301 -0.0000 0.0054
*CONTROL_ROT_SAMPLE 17760 0.9995 -0.0302 0.0000 0.0049
*CONTROL_ROT_SAMPLE 17920 0.9995 -0.0301 0.0000 0.0044
*CONTROL_ROT_SAMPLE 18080 0.9995 -0.0302 -0.0000 0.0039
*CONTROL_ROT_SAMPLE 18240 0.9995 -0.0301 0.0000 0.0035
*CONTROL_ROT_SAMPLE 18400 0.9995 -0.0301 0.0000 0.0029
*CONTROL_ROT_SAMPLE 18560 0.9995 -0.0301 0.0000 0.0024
*CONTROL_ROT_SAMPLE 18720 0.9995 -0.0301 0.0000 0.0019
*CONTROL_ROT_SAMPLE 18880 0.9995 -0.0301 -0.0000 0.0014
*CONTROL_ROT_SAMPLE 19040 0.9995 -0.0301 0.0000 0.0008
*CONTROL_ROT_SAMPLE 19200 0.9995 -0.0302 0.0000 0.0003
}
}
}

View File

@ -0,0 +1,655 @@
*3DSMAX_ASCIIEXPORT 200
*COMMENT "AsciiExport Version 2,00 - Sat Nov 08 17:59:18 2008"
*SCENE {
*SCENE_FILENAME "CameraRollAnimWithChildObject.max"
*SCENE_FIRSTFRAME 0
*SCENE_LASTFRAME 300
*SCENE_FRAMESPEED 30
*SCENE_TICKSPERFRAME 160
*SCENE_BACKGROUND_STATIC 0.0000 0.0000 0.0000
*SCENE_AMBIENT_STATIC 0.0000 0.0000 0.0000
}
*MATERIAL_LIST {
*MATERIAL_COUNT 0
}
*GEOMOBJECT {
*NODE_NAME "Box01"
*NODE_TM {
*NODE_NAME "Box01"
*INHERIT_POS 0 0 0
*INHERIT_ROT 0 0 0
*INHERIT_SCL 0 0 0
*TM_ROW0 1.0000 0.0000 0.0000
*TM_ROW1 0.0000 1.0000 0.0000
*TM_ROW2 0.0000 0.0000 1.0000
*TM_ROW3 10.5413 -0.8547 0.0000
*TM_POS 10.5413 -0.8547 0.0000
*TM_ROTAXIS 0.0000 0.0000 0.0000
*TM_ROTANGLE 0.0000
*TM_SCALE 1.0000 1.0000 1.0000
*TM_SCALEAXIS 0.0000 0.0000 0.0000
*TM_SCALEAXISANG 0.0000
}
*MESH {
*TIMEVALUE 0
*MESH_NUMVERTEX 8
*MESH_NUMFACES 12
*MESH_VERTEX_LIST {
*MESH_VERTEX 0 -24.7863 -24.7863 0.0000
*MESH_VERTEX 1 45.8689 -24.7863 0.0000
*MESH_VERTEX 2 -24.7863 23.0769 0.0000
*MESH_VERTEX 3 45.8689 23.0769 0.0000
*MESH_VERTEX 4 -24.7863 -24.7863 38.7464
*MESH_VERTEX 5 45.8689 -24.7863 38.7464
*MESH_VERTEX 6 -24.7863 23.0769 38.7464
*MESH_VERTEX 7 45.8689 23.0769 38.7464
}
*MESH_FACE_LIST {
*MESH_FACE 0: A: 0 B: 2 C: 3 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 2 *MESH_MTLID 1
*MESH_FACE 1: A: 3 B: 1 C: 0 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 2 *MESH_MTLID 1
*MESH_FACE 2: A: 4 B: 5 C: 7 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 3 *MESH_MTLID 0
*MESH_FACE 3: A: 7 B: 6 C: 4 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 3 *MESH_MTLID 0
*MESH_FACE 4: A: 0 B: 1 C: 5 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 4 *MESH_MTLID 4
*MESH_FACE 5: A: 5 B: 4 C: 0 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 4 *MESH_MTLID 4
*MESH_FACE 6: A: 1 B: 3 C: 7 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 5 *MESH_MTLID 3
*MESH_FACE 7: A: 7 B: 5 C: 1 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 5 *MESH_MTLID 3
*MESH_FACE 8: A: 3 B: 2 C: 6 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 6 *MESH_MTLID 5
*MESH_FACE 9: A: 6 B: 7 C: 3 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 6 *MESH_MTLID 5
*MESH_FACE 10: A: 2 B: 0 C: 4 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 7 *MESH_MTLID 2
*MESH_FACE 11: A: 4 B: 6 C: 2 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 7 *MESH_MTLID 2
}
*MESH_NUMTVERTEX 12
*MESH_TVERTLIST {
*MESH_TVERT 0 0.0000 0.0000 0.0000
*MESH_TVERT 1 1.0000 0.0000 0.0000
*MESH_TVERT 2 0.0000 1.0000 0.0000
*MESH_TVERT 3 1.0000 1.0000 0.0000
*MESH_TVERT 4 0.0000 0.0000 0.0000
*MESH_TVERT 5 1.0000 0.0000 0.0000
*MESH_TVERT 6 0.0000 1.0000 0.0000
*MESH_TVERT 7 1.0000 1.0000 0.0000
*MESH_TVERT 8 0.0000 0.0000 0.0000
*MESH_TVERT 9 1.0000 0.0000 0.0000
*MESH_TVERT 10 0.0000 1.0000 0.0000
*MESH_TVERT 11 1.0000 1.0000 0.0000
}
*MESH_NUMTVFACES 12
*MESH_TFACELIST {
*MESH_TFACE 0 9 11 10
*MESH_TFACE 1 10 8 9
*MESH_TFACE 2 8 9 11
*MESH_TFACE 3 11 10 8
*MESH_TFACE 4 4 5 7
*MESH_TFACE 5 7 6 4
*MESH_TFACE 6 0 1 3
*MESH_TFACE 7 3 2 0
*MESH_TFACE 8 4 5 7
*MESH_TFACE 9 7 6 4
*MESH_TFACE 10 0 1 3
*MESH_TFACE 11 3 2 0
}
*MESH_NUMCVERTEX 0
*MESH_NORMALS {
*MESH_FACENORMAL 0 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 0 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 2 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 3 0.0000 0.0000 -1.0000
*MESH_FACENORMAL 1 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 3 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 1 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 0 0.0000 0.0000 -1.0000
*MESH_FACENORMAL 2 0.0000 -0.0000 1.0000
*MESH_VERTEXNORMAL 4 0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 5 0.0000 -0.0000 1.0000
*MESH_VERTEXNORMAL 7 0.0000 0.0000 1.0000
*MESH_FACENORMAL 3 -0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 7 0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 6 -0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 4 0.0000 0.0000 1.0000
*MESH_FACENORMAL 4 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 0 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 1 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 5 0.0000 -1.0000 0.0000
*MESH_FACENORMAL 5 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 5 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 4 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 0 0.0000 -1.0000 0.0000
*MESH_FACENORMAL 6 1.0000 0.0000 -0.0000
*MESH_VERTEXNORMAL 1 1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 3 1.0000 0.0000 -0.0000
*MESH_VERTEXNORMAL 7 1.0000 0.0000 0.0000
*MESH_FACENORMAL 7 1.0000 -0.0000 0.0000
*MESH_VERTEXNORMAL 7 1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 5 1.0000 -0.0000 0.0000
*MESH_VERTEXNORMAL 1 1.0000 0.0000 0.0000
*MESH_FACENORMAL 8 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 3 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 2 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 6 0.0000 1.0000 0.0000
*MESH_FACENORMAL 9 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 6 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 7 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 3 0.0000 1.0000 0.0000
*MESH_FACENORMAL 10 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 2 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 0 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 4 -1.0000 0.0000 0.0000
*MESH_FACENORMAL 11 -1.0000 -0.0000 -0.0000
*MESH_VERTEXNORMAL 4 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 6 -1.0000 -0.0000 -0.0000
*MESH_VERTEXNORMAL 2 -1.0000 0.0000 0.0000
}
}
*PROP_MOTIONBLUR 0
*PROP_CASTSHADOW 1
*PROP_RECVSHADOW 1
*WIREFRAME_COLOR 0.6941 0.3451 0.1059
}
*CAMERAOBJECT {
*NODE_NAME "Camera01"
*CAMERA_TYPE Target
*NODE_TM {
*NODE_NAME "Camera01"
*INHERIT_POS 0 0 0
*INHERIT_ROT 0 0 0
*INHERIT_SCL 1 1 1
*TM_ROW0 -0.0301 -0.9995 -0.0000
*TM_ROW1 -0.0194 0.0006 0.9998
*TM_ROW2 -0.9994 0.0301 -0.0194
*TM_ROW3 -152.3626 3.2505 22.7915
*TM_POS -152.3626 3.2505 22.7915
*TM_ROTAXIS 0.5694 -0.5869 -0.5756
*TM_ROTANGLE 4.1603
*TM_SCALE 1.0000 1.0000 1.0000
*TM_SCALEAXIS 0.2700 -0.9628 -0.0060
*TM_SCALEAXISANG 0.0243
}
*NODE_TM {
*NODE_NAME "Camera01.Target"
*INHERIT_POS 0 0 0
*INHERIT_ROT 0 0 0
*INHERIT_SCL 0 0 0
*TM_ROW0 1.0000 0.0000 0.0000
*TM_ROW1 0.0000 1.0000 0.0000
*TM_ROW2 0.0000 0.0000 1.0000
*TM_ROW3 -36.5134 -0.2420 25.0386
*TM_POS -36.5134 -0.2420 25.0386
*TM_ROTAXIS 0.0000 0.0000 0.0000
*TM_ROTANGLE 0.0000
*TM_SCALE 1.0000 1.0000 1.0000
*TM_SCALEAXIS 0.0000 0.0000 0.0000
*TM_SCALEAXISANG 0.0000
}
*CAMERA_SETTINGS {
*TIMEVALUE 0
*CAMERA_NEAR 0.0000
*CAMERA_FAR 1000.0000
*CAMERA_FOV 0.7854
*CAMERA_TDIST 115.9236
}
*TM_ANIMATION {
*NODE_NAME "Camera01"
*CONTROL_ROT_TRACK {
*CONTROL_ROT_SAMPLE 0 0.5694 -0.5869 -0.5756 4.1603
*CONTROL_ROT_SAMPLE 160 0.9869 0.1603 0.0186 0.0003
*CONTROL_ROT_SAMPLE 320 0.9869 0.1602 0.0193 0.0008
*CONTROL_ROT_SAMPLE 480 0.9869 0.1599 0.0194 0.0014
*CONTROL_ROT_SAMPLE 640 0.9870 0.1595 0.0197 0.0019
*CONTROL_ROT_SAMPLE 800 0.9870 0.1592 0.0201 0.0025
*CONTROL_ROT_SAMPLE 960 0.9871 0.1588 0.0206 0.0030
*CONTROL_ROT_SAMPLE 1120 0.9871 0.1585 0.0212 0.0035
*CONTROL_ROT_SAMPLE 1280 0.9872 0.1582 0.0219 0.0040
*CONTROL_ROT_SAMPLE 1440 0.9872 0.1578 0.0227 0.0045
*CONTROL_ROT_SAMPLE 1600 0.9872 0.1575 0.0236 0.0050
*CONTROL_ROT_SAMPLE 1760 0.9873 0.1571 0.0245 0.0055
*CONTROL_ROT_SAMPLE 1920 0.9873 0.1567 0.0256 0.0059
*CONTROL_ROT_SAMPLE 2080 0.9873 0.1563 0.0267 0.0064
*CONTROL_ROT_SAMPLE 2240 0.9874 0.1559 0.0279 0.0068
*CONTROL_ROT_SAMPLE 2400 0.9874 0.1555 0.0292 0.0073
*CONTROL_ROT_SAMPLE 2560 -0.9874 -0.1551 -0.0306 6.2755
*CONTROL_ROT_SAMPLE 2720 0.9875 0.1546 0.0320 0.0081
*CONTROL_ROT_SAMPLE 2880 0.9875 0.1542 0.0335 0.0085
*CONTROL_ROT_SAMPLE 3040 0.9875 0.1538 0.0351 0.0089
*CONTROL_ROT_SAMPLE 3200 0.9875 0.1533 0.0368 0.0093
*CONTROL_ROT_SAMPLE 3360 0.9875 0.1528 0.0385 0.0097
*CONTROL_ROT_SAMPLE 3520 0.9875 0.1524 0.0403 0.0101
*CONTROL_ROT_SAMPLE 3680 0.9875 0.1519 0.0421 0.0104
*CONTROL_ROT_SAMPLE 3840 0.9875 0.1514 0.0440 0.0108
*CONTROL_ROT_SAMPLE 4000 0.9875 0.1509 0.0459 0.0111
*CONTROL_ROT_SAMPLE 4160 0.9875 0.1504 0.0479 0.0115
*CONTROL_ROT_SAMPLE 4320 0.9874 0.1498 0.0500 0.0118
*CONTROL_ROT_SAMPLE 4480 0.9874 0.1493 0.0521 0.0121
*CONTROL_ROT_SAMPLE 4640 0.9874 0.1487 0.0543 0.0124
*CONTROL_ROT_SAMPLE 4800 0.9874 0.1481 0.0565 0.0127
*CONTROL_ROT_SAMPLE 4960 0.9873 0.1475 0.0587 0.0130
*CONTROL_ROT_SAMPLE 5120 0.9873 0.1469 0.0610 0.0133
*CONTROL_ROT_SAMPLE 5280 0.9872 0.1463 0.0633 0.0135
*CONTROL_ROT_SAMPLE 5440 0.9871 0.1457 0.0657 0.0138
*CONTROL_ROT_SAMPLE 5600 0.9871 0.1450 0.0681 0.0140
*CONTROL_ROT_SAMPLE 5760 0.9870 0.1443 0.0705 0.0143
*CONTROL_ROT_SAMPLE 5920 0.9869 0.1437 0.0730 0.0145
*CONTROL_ROT_SAMPLE 6080 0.9868 0.1430 0.0755 0.0147
*CONTROL_ROT_SAMPLE 6240 0.9868 0.1422 0.0780 0.0149
*CONTROL_ROT_SAMPLE 6400 0.9867 0.1415 0.0805 0.0151
*CONTROL_ROT_SAMPLE 6560 0.9866 0.1407 0.0831 0.0153
*CONTROL_ROT_SAMPLE 6720 0.9864 0.1400 0.0857 0.0155
*CONTROL_ROT_SAMPLE 6880 0.9863 0.1392 0.0883 0.0156
*CONTROL_ROT_SAMPLE 7040 0.9862 0.1383 0.0909 0.0158
*CONTROL_ROT_SAMPLE 7200 0.9861 0.1375 0.0935 0.0160
*CONTROL_ROT_SAMPLE 7360 0.9859 0.1366 0.0961 0.0161
*CONTROL_ROT_SAMPLE 7520 0.9858 0.1357 0.0988 0.0162
*CONTROL_ROT_SAMPLE 7680 0.9857 0.1348 0.1014 0.0163
*CONTROL_ROT_SAMPLE 7840 0.9855 0.1339 0.1041 0.0165
*CONTROL_ROT_SAMPLE 8000 0.9854 0.1329 0.1067 0.0166
*CONTROL_ROT_SAMPLE 8160 0.9852 0.1319 0.1094 0.0166
*CONTROL_ROT_SAMPLE 8320 0.9850 0.1309 0.1121 0.0167
*CONTROL_ROT_SAMPLE 8480 0.9849 0.1299 0.1147 0.0168
*CONTROL_ROT_SAMPLE 8640 0.9847 0.1288 0.1174 0.0169
*CONTROL_ROT_SAMPLE 8800 0.9845 0.1277 0.1200 0.0169
*CONTROL_ROT_SAMPLE 8960 0.9844 0.1265 0.1226 0.0170
*CONTROL_ROT_SAMPLE 9120 0.9842 0.1254 0.1252 0.0170
*CONTROL_ROT_SAMPLE 9280 0.9840 0.1242 0.1278 0.0170
*CONTROL_ROT_SAMPLE 9440 0.9838 0.1229 0.1304 0.0170
*CONTROL_ROT_SAMPLE 9600 0.9836 0.1216 0.1330 0.0170
*CONTROL_ROT_SAMPLE 9760 0.9834 0.1203 0.1355 0.0170
*CONTROL_ROT_SAMPLE 9920 0.9833 0.1189 0.1380 0.0170
*CONTROL_ROT_SAMPLE 10080 0.9831 0.1175 0.1405 0.0170
*CONTROL_ROT_SAMPLE 10240 0.9829 0.1161 0.1430 0.0170
*CONTROL_ROT_SAMPLE 10400 0.9827 0.1146 0.1454 0.0169
*CONTROL_ROT_SAMPLE 10560 0.9825 0.1130 0.1478 0.0169
*CONTROL_ROT_SAMPLE 10720 0.9824 0.1114 0.1502 0.0168
*CONTROL_ROT_SAMPLE 10880 0.9822 0.1097 0.1525 0.0168
*CONTROL_ROT_SAMPLE 11040 0.9820 0.1080 0.1548 0.0167
*CONTROL_ROT_SAMPLE 11200 0.9819 0.1062 0.1571 0.0166
*CONTROL_ROT_SAMPLE 11360 0.9817 0.1043 0.1593 0.0165
*CONTROL_ROT_SAMPLE 11520 0.9815 0.1024 0.1615 0.0164
*CONTROL_ROT_SAMPLE 11680 0.9814 0.1004 0.1636 0.0163
*CONTROL_ROT_SAMPLE 11840 0.9813 0.0983 0.1657 0.0161
*CONTROL_ROT_SAMPLE 12000 0.9811 0.0962 0.1678 0.0160
*CONTROL_ROT_SAMPLE 12160 0.9810 0.0939 0.1697 0.0158
*CONTROL_ROT_SAMPLE 12320 0.9809 0.0915 0.1717 0.0157
*CONTROL_ROT_SAMPLE 12480 0.9808 0.0891 0.1736 0.0155
*CONTROL_ROT_SAMPLE 12640 0.9807 0.0865 0.1754 0.0154
*CONTROL_ROT_SAMPLE 12800 0.9806 0.0838 0.1771 0.0152
*CONTROL_ROT_SAMPLE 12960 0.9805 0.0810 0.1789 0.0150
*CONTROL_ROT_SAMPLE 13120 0.9805 0.0780 0.1805 0.0148
*CONTROL_ROT_SAMPLE 13280 0.9804 0.0749 0.1821 0.0146
*CONTROL_ROT_SAMPLE 13440 0.9804 0.0716 0.1836 0.0143
*CONTROL_ROT_SAMPLE 13600 0.9804 0.0681 0.1850 0.0141
*CONTROL_ROT_SAMPLE 13760 0.9804 0.0644 0.1864 0.0139
*CONTROL_ROT_SAMPLE 13920 0.9804 0.0606 0.1877 0.0136
*CONTROL_ROT_SAMPLE 14080 0.9804 0.0564 0.1890 0.0134
*CONTROL_ROT_SAMPLE 14240 0.9804 0.0521 0.1901 0.0131
*CONTROL_ROT_SAMPLE 14400 0.9804 0.0474 0.1912 0.0128
*CONTROL_ROT_SAMPLE 14560 0.9804 0.0424 0.1922 0.0125
*CONTROL_ROT_SAMPLE 14720 0.9805 0.0371 0.1931 0.0122
*CONTROL_ROT_SAMPLE 14880 0.9805 0.0314 0.1939 0.0119
*CONTROL_ROT_SAMPLE 15040 0.9805 0.0253 0.1946 0.0116
*CONTROL_ROT_SAMPLE 15200 0.9806 0.0187 0.1953 0.0113
*CONTROL_ROT_SAMPLE 15360 0.9806 0.0115 0.1958 0.0110
*CONTROL_ROT_SAMPLE 15520 0.9805 0.0038 0.1963 0.0106
*CONTROL_ROT_SAMPLE 15680 0.9805 -0.0047 0.1966 0.0103
*CONTROL_ROT_SAMPLE 15840 0.9803 -0.0140 0.1969 0.0099
*CONTROL_ROT_SAMPLE 16000 0.9801 -0.0241 0.1970 0.0095
*CONTROL_ROT_SAMPLE 16160 0.9800 -0.0295 0.1970 0.0092
*CONTROL_ROT_SAMPLE 16320 0.9800 -0.0295 0.1970 0.0088
*CONTROL_ROT_SAMPLE 16480 0.9800 -0.0296 0.1970 0.0084
*CONTROL_ROT_SAMPLE 16640 0.9800 -0.0295 0.1970 0.0080
*CONTROL_ROT_SAMPLE 16800 0.9800 -0.0295 0.1970 0.0076
*CONTROL_ROT_SAMPLE 16960 0.9800 -0.0296 0.1970 0.0072
*CONTROL_ROT_SAMPLE 17120 0.9800 -0.0295 0.1970 0.0067
*CONTROL_ROT_SAMPLE 17280 0.9800 -0.0295 0.1970 0.0063
*CONTROL_ROT_SAMPLE 17440 0.9800 -0.0296 0.1970 0.0058
*CONTROL_ROT_SAMPLE 17600 0.9800 -0.0295 0.1970 0.0054
*CONTROL_ROT_SAMPLE 17760 0.9800 -0.0295 0.1970 0.0049
*CONTROL_ROT_SAMPLE 17920 0.9800 -0.0296 0.1970 0.0044
*CONTROL_ROT_SAMPLE 18080 0.9800 -0.0295 0.1970 0.0039
*CONTROL_ROT_SAMPLE 18240 0.9800 -0.0295 0.1970 0.0035
*CONTROL_ROT_SAMPLE 18400 0.9800 -0.0295 0.1970 0.0029
*CONTROL_ROT_SAMPLE 18560 0.9800 -0.0295 0.1970 0.0024
*CONTROL_ROT_SAMPLE 18720 0.9800 -0.0295 0.1970 0.0019
*CONTROL_ROT_SAMPLE 18880 0.9800 -0.0296 0.1970 0.0014
*CONTROL_ROT_SAMPLE 19040 0.9799 -0.0295 0.1971 0.0008
*CONTROL_ROT_SAMPLE 19200 0.9800 -0.0297 0.1970 0.0003
}
}
*TM_ANIMATION {
*NODE_NAME "Camera01.Target"
*CONTROL_POS_TRACK {
*CONTROL_POS_SAMPLE 0 -36.5134 -0.2420 25.0386
*CONTROL_POS_SAMPLE 160 -36.5134 -0.2420 25.0449
*CONTROL_POS_SAMPLE 320 -36.5134 -0.2420 25.0635
*CONTROL_POS_SAMPLE 480 -36.5134 -0.2420 25.0943
*CONTROL_POS_SAMPLE 640 -36.5134 -0.2420 25.1370
*CONTROL_POS_SAMPLE 800 -36.5134 -0.2420 25.1912
*CONTROL_POS_SAMPLE 960 -36.5134 -0.2420 25.2568
*CONTROL_POS_SAMPLE 1120 -36.5134 -0.2420 25.3336
*CONTROL_POS_SAMPLE 1280 -36.5134 -0.2420 25.4212
*CONTROL_POS_SAMPLE 1440 -36.5134 -0.2420 25.5194
*CONTROL_POS_SAMPLE 1600 -36.5134 -0.2420 25.6279
*CONTROL_POS_SAMPLE 1760 -36.5134 -0.2420 25.7466
*CONTROL_POS_SAMPLE 1920 -36.5134 -0.2420 25.8751
*CONTROL_POS_SAMPLE 2080 -36.5134 -0.2420 26.0132
*CONTROL_POS_SAMPLE 2240 -36.5134 -0.2420 26.1606
*CONTROL_POS_SAMPLE 2400 -36.5134 -0.2420 26.3172
*CONTROL_POS_SAMPLE 2560 -36.5134 -0.2420 26.4826
*CONTROL_POS_SAMPLE 2720 -36.5134 -0.2420 26.6565
*CONTROL_POS_SAMPLE 2880 -36.5134 -0.2420 26.8388
*CONTROL_POS_SAMPLE 3040 -36.5134 -0.2420 27.0292
*CONTROL_POS_SAMPLE 3200 -36.5134 -0.2420 27.2274
*CONTROL_POS_SAMPLE 3360 -36.5134 -0.2420 27.4332
*CONTROL_POS_SAMPLE 3520 -36.5134 -0.2420 27.6463
*CONTROL_POS_SAMPLE 3680 -36.5134 -0.2420 27.8665
*CONTROL_POS_SAMPLE 3840 -36.5134 -0.2420 28.0935
*CONTROL_POS_SAMPLE 4000 -36.5134 -0.2420 28.3271
*CONTROL_POS_SAMPLE 4160 -36.5134 -0.2420 28.5670
*CONTROL_POS_SAMPLE 4320 -36.5134 -0.2420 28.8129
*CONTROL_POS_SAMPLE 4480 -36.5134 -0.2420 29.0646
*CONTROL_POS_SAMPLE 4640 -36.5134 -0.2420 29.3220
*CONTROL_POS_SAMPLE 4800 -36.5134 -0.2420 29.5846
*CONTROL_POS_SAMPLE 4960 -36.5134 -0.2420 29.8522
*CONTROL_POS_SAMPLE 5120 -36.5134 -0.2420 30.1247
*CONTROL_POS_SAMPLE 5280 -36.5134 -0.2420 30.4017
*CONTROL_POS_SAMPLE 5440 -36.5134 -0.2420 30.6830
*CONTROL_POS_SAMPLE 5600 -36.5134 -0.2420 30.9683
*CONTROL_POS_SAMPLE 5760 -36.5134 -0.2420 31.2575
*CONTROL_POS_SAMPLE 5920 -36.5134 -0.2420 31.5501
*CONTROL_POS_SAMPLE 6080 -36.5134 -0.2420 31.8461
*CONTROL_POS_SAMPLE 6240 -36.5134 -0.2420 32.1451
*CONTROL_POS_SAMPLE 6400 -36.5134 -0.2420 32.4468
*CONTROL_POS_SAMPLE 6560 -36.5134 -0.2420 32.7511
*CONTROL_POS_SAMPLE 6720 -36.5134 -0.2420 33.0577
*CONTROL_POS_SAMPLE 6880 -36.5134 -0.2420 33.3662
*CONTROL_POS_SAMPLE 7040 -36.5134 -0.2420 33.6766
*CONTROL_POS_SAMPLE 7200 -36.5134 -0.2420 33.9884
*CONTROL_POS_SAMPLE 7360 -36.5134 -0.2420 34.3016
*CONTROL_POS_SAMPLE 7520 -36.5134 -0.2420 34.6157
*CONTROL_POS_SAMPLE 7680 -36.5134 -0.2420 34.9306
*CONTROL_POS_SAMPLE 7840 -36.5134 -0.2420 35.2460
*CONTROL_POS_SAMPLE 8000 -36.5134 -0.2420 35.5616
*CONTROL_POS_SAMPLE 8160 -36.5134 -0.2420 35.8773
*CONTROL_POS_SAMPLE 8320 -36.5134 -0.2420 36.1927
*CONTROL_POS_SAMPLE 8480 -36.5134 -0.2420 36.5076
*CONTROL_POS_SAMPLE 8640 -36.5134 -0.2420 36.8217
*CONTROL_POS_SAMPLE 8800 -36.5134 -0.2420 37.1348
*CONTROL_POS_SAMPLE 8960 -36.5134 -0.2420 37.4467
*CONTROL_POS_SAMPLE 9120 -36.5134 -0.2420 37.7570
*CONTROL_POS_SAMPLE 9280 -36.5134 -0.2420 38.0656
*CONTROL_POS_SAMPLE 9440 -36.5134 -0.2420 38.3722
*CONTROL_POS_SAMPLE 9600 -36.5134 -0.2420 38.6764
*CONTROL_POS_SAMPLE 9760 -36.5134 -0.2420 38.9782
*CONTROL_POS_SAMPLE 9920 -36.5134 -0.2420 39.2772
*CONTROL_POS_SAMPLE 10080 -36.5134 -0.2420 39.5731
*CONTROL_POS_SAMPLE 10240 -36.5134 -0.2420 39.8658
*CONTROL_POS_SAMPLE 10400 -36.5134 -0.2420 40.1549
*CONTROL_POS_SAMPLE 10560 -36.5134 -0.2420 40.4403
*CONTROL_POS_SAMPLE 10720 -36.5134 -0.2420 40.7216
*CONTROL_POS_SAMPLE 10880 -36.5134 -0.2420 40.9986
*CONTROL_POS_SAMPLE 11040 -36.5134 -0.2420 41.2710
*CONTROL_POS_SAMPLE 11200 -36.5134 -0.2420 41.5387
*CONTROL_POS_SAMPLE 11360 -36.5134 -0.2420 41.8013
*CONTROL_POS_SAMPLE 11520 -36.5134 -0.2420 42.0586
*CONTROL_POS_SAMPLE 11680 -36.5134 -0.2420 42.3104
*CONTROL_POS_SAMPLE 11840 -36.5134 -0.2420 42.5563
*CONTROL_POS_SAMPLE 12000 -36.5134 -0.2420 42.7962
*CONTROL_POS_SAMPLE 12160 -36.5134 -0.2420 43.0298
*CONTROL_POS_SAMPLE 12320 -36.5134 -0.2420 43.2568
*CONTROL_POS_SAMPLE 12480 -36.5134 -0.2420 43.4769
*CONTROL_POS_SAMPLE 12640 -36.5134 -0.2420 43.6901
*CONTROL_POS_SAMPLE 12800 -36.5134 -0.2420 43.8958
*CONTROL_POS_SAMPLE 12960 -36.5134 -0.2420 44.0941
*CONTROL_POS_SAMPLE 13120 -36.5134 -0.2420 44.2844
*CONTROL_POS_SAMPLE 13280 -36.5134 -0.2420 44.4667
*CONTROL_POS_SAMPLE 13440 -36.5134 -0.2420 44.6407
*CONTROL_POS_SAMPLE 13600 -36.5134 -0.2420 44.8061
*CONTROL_POS_SAMPLE 13760 -36.5134 -0.2420 44.9626
*CONTROL_POS_SAMPLE 13920 -36.5134 -0.2420 45.1101
*CONTROL_POS_SAMPLE 14080 -36.5134 -0.2420 45.2482
*CONTROL_POS_SAMPLE 14240 -36.5134 -0.2420 45.3767
*CONTROL_POS_SAMPLE 14400 -36.5134 -0.2420 45.4953
*CONTROL_POS_SAMPLE 14560 -36.5134 -0.2420 45.6039
*CONTROL_POS_SAMPLE 14720 -36.5134 -0.2420 45.7021
*CONTROL_POS_SAMPLE 14880 -36.5134 -0.2420 45.7897
*CONTROL_POS_SAMPLE 15040 -36.5134 -0.2420 45.8664
*CONTROL_POS_SAMPLE 15200 -36.5134 -0.2420 45.9320
*CONTROL_POS_SAMPLE 15360 -36.5134 -0.2420 45.9863
*CONTROL_POS_SAMPLE 15520 -36.5134 -0.2420 46.0289
*CONTROL_POS_SAMPLE 15680 -36.5134 -0.2420 46.0597
*CONTROL_POS_SAMPLE 15840 -36.5134 -0.2420 46.0784
*CONTROL_POS_SAMPLE 16000 -36.5134 -0.2420 46.0846
}
}
}
*GEOMOBJECT {
*NODE_NAME "Box02"
*NODE_PARENT "Camera01"
*NODE_TM {
*NODE_NAME "Box02"
*INHERIT_POS 0 0 0
*INHERIT_ROT 0 0 0
*INHERIT_SCL 0 0 0
*TM_ROW0 0.9998 0.0000 0.0195
*TM_ROW1 -0.0001 1.0000 0.0028
*TM_ROW2 -0.0195 -0.0028 0.9998
*TM_ROW3 -15.3872 -72.2765 2.4662
*TM_POS -15.3872 -72.2765 2.4662
*TM_ROTAXIS -0.1436 0.9896 -0.0017
*TM_ROTANGLE 0.0197
*TM_SCALE 1.0000 1.0000 1.0000
*TM_SCALEAXIS 0.1219 -0.6686 0.7336
*TM_SCALEAXISANG 0.0099
}
*MESH {
*TIMEVALUE 0
*MESH_NUMVERTEX 8
*MESH_NUMFACES 12
*MESH_VERTEX_LIST {
*MESH_VERTEX 0 -54.4096 -97.3479 1.6351
*MESH_VERTEX 1 23.6383 -97.3474 3.1556
*MESH_VERTEX 2 -54.4126 -47.2056 1.7768
*MESH_VERTEX 3 23.6353 -47.2052 3.2974
*MESH_VERTEX 4 -54.8868 -97.4171 26.1318
*MESH_VERTEX 5 23.1610 -97.4167 27.6523
*MESH_VERTEX 6 -54.8899 -47.2749 26.2735
*MESH_VERTEX 7 23.1580 -47.2744 27.7940
}
*MESH_FACE_LIST {
*MESH_FACE 0: A: 0 B: 2 C: 3 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 2 *MESH_MTLID 1
*MESH_FACE 1: A: 3 B: 1 C: 0 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 2 *MESH_MTLID 1
*MESH_FACE 2: A: 4 B: 5 C: 7 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 3 *MESH_MTLID 0
*MESH_FACE 3: A: 7 B: 6 C: 4 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 3 *MESH_MTLID 0
*MESH_FACE 4: A: 0 B: 1 C: 5 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 4 *MESH_MTLID 4
*MESH_FACE 5: A: 5 B: 4 C: 0 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 4 *MESH_MTLID 4
*MESH_FACE 6: A: 1 B: 3 C: 7 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 5 *MESH_MTLID 3
*MESH_FACE 7: A: 7 B: 5 C: 1 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 5 *MESH_MTLID 3
*MESH_FACE 8: A: 3 B: 2 C: 6 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 6 *MESH_MTLID 5
*MESH_FACE 9: A: 6 B: 7 C: 3 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 6 *MESH_MTLID 5
*MESH_FACE 10: A: 2 B: 0 C: 4 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 7 *MESH_MTLID 2
*MESH_FACE 11: A: 4 B: 6 C: 2 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 7 *MESH_MTLID 2
}
*MESH_NUMTVERTEX 12
*MESH_TVERTLIST {
*MESH_TVERT 0 0.0000 0.0000 0.0000
*MESH_TVERT 1 1.0000 0.0000 0.0000
*MESH_TVERT 2 0.0000 1.0000 0.0000
*MESH_TVERT 3 1.0000 1.0000 0.0000
*MESH_TVERT 4 0.0000 0.0000 0.0000
*MESH_TVERT 5 1.0000 0.0000 0.0000
*MESH_TVERT 6 0.0000 1.0000 0.0000
*MESH_TVERT 7 1.0000 1.0000 0.0000
*MESH_TVERT 8 0.0000 0.0000 0.0000
*MESH_TVERT 9 1.0000 0.0000 0.0000
*MESH_TVERT 10 0.0000 1.0000 0.0000
*MESH_TVERT 11 1.0000 1.0000 0.0000
}
*MESH_NUMTVFACES 12
*MESH_TFACELIST {
*MESH_TFACE 0 9 11 10
*MESH_TFACE 1 10 8 9
*MESH_TFACE 2 8 9 11
*MESH_TFACE 3 11 10 8
*MESH_TFACE 4 4 5 7
*MESH_TFACE 5 7 6 4
*MESH_TFACE 6 0 1 3
*MESH_TFACE 7 3 2 0
*MESH_TFACE 8 4 5 7
*MESH_TFACE 9 7 6 4
*MESH_TFACE 10 0 1 3
*MESH_TFACE 11 3 2 0
}
*MESH_NUMCVERTEX 0
*MESH_NORMALS {
*MESH_FACENORMAL 0 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 0 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 2 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 3 0.0000 0.0000 -1.0000
*MESH_FACENORMAL 1 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 3 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 1 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 0 0.0000 0.0000 -1.0000
*MESH_FACENORMAL 2 0.0000 -0.0000 1.0000
*MESH_VERTEXNORMAL 4 0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 5 0.0000 -0.0000 1.0000
*MESH_VERTEXNORMAL 7 0.0000 0.0000 1.0000
*MESH_FACENORMAL 3 -0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 7 0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 6 -0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 4 0.0000 0.0000 1.0000
*MESH_FACENORMAL 4 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 0 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 1 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 5 0.0000 -1.0000 0.0000
*MESH_FACENORMAL 5 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 5 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 4 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 0 0.0000 -1.0000 0.0000
*MESH_FACENORMAL 6 1.0000 0.0000 -0.0000
*MESH_VERTEXNORMAL 1 1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 3 1.0000 0.0000 -0.0000
*MESH_VERTEXNORMAL 7 1.0000 0.0000 0.0000
*MESH_FACENORMAL 7 1.0000 -0.0000 0.0000
*MESH_VERTEXNORMAL 7 1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 5 1.0000 -0.0000 0.0000
*MESH_VERTEXNORMAL 1 1.0000 0.0000 0.0000
*MESH_FACENORMAL 8 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 3 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 2 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 6 0.0000 1.0000 0.0000
*MESH_FACENORMAL 9 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 6 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 7 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 3 0.0000 1.0000 0.0000
*MESH_FACENORMAL 10 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 2 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 0 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 4 -1.0000 0.0000 0.0000
*MESH_FACENORMAL 11 -1.0000 -0.0000 -0.0000
*MESH_VERTEXNORMAL 4 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 6 -1.0000 -0.0000 -0.0000
*MESH_VERTEXNORMAL 2 -1.0000 0.0000 0.0000
}
}
*PROP_MOTIONBLUR 0
*PROP_CASTSHADOW 1
*PROP_RECVSHADOW 1
*TM_ANIMATION {
*NODE_NAME "Box02"
*CONTROL_POS_TRACK {
*CONTROL_POS_SAMPLE 0 71.3652 -23.0196 -138.7689
*CONTROL_POS_SAMPLE 160 71.3603 -23.0080 -138.7694
*CONTROL_POS_SAMPLE 320 71.3456 -22.9735 -138.7706
*CONTROL_POS_SAMPLE 480 71.3213 -22.9167 -138.7726
*CONTROL_POS_SAMPLE 640 71.2877 -22.8379 -138.7755
*CONTROL_POS_SAMPLE 800 71.2450 -22.7378 -138.7790
*CONTROL_POS_SAMPLE 960 71.1935 -22.6169 -138.7834
*CONTROL_POS_SAMPLE 1120 71.1332 -22.4756 -138.7884
*CONTROL_POS_SAMPLE 1280 71.0645 -22.3144 -138.7942
*CONTROL_POS_SAMPLE 1440 70.9875 -22.1339 -138.8007
*CONTROL_POS_SAMPLE 1600 70.9025 -21.9345 -138.8078
*CONTROL_POS_SAMPLE 1760 70.8096 -21.7167 -138.8156
*CONTROL_POS_SAMPLE 1920 70.7091 -21.4812 -138.8241
*CONTROL_POS_SAMPLE 2080 70.6013 -21.2282 -138.8331
*CONTROL_POS_SAMPLE 2240 70.4863 -20.9584 -138.8428
*CONTROL_POS_SAMPLE 2400 70.3642 -20.6723 -138.8530
*CONTROL_POS_SAMPLE 2560 70.2355 -20.3704 -138.8639
*CONTROL_POS_SAMPLE 2720 70.1002 -20.0531 -138.8752
*CONTROL_POS_SAMPLE 2880 69.9585 -19.7210 -138.8871
*CONTROL_POS_SAMPLE 3040 69.8108 -19.3745 -138.8996
*CONTROL_POS_SAMPLE 3200 69.6572 -19.0143 -138.9124
*CONTROL_POS_SAMPLE 3360 69.4979 -18.6407 -138.9259
*CONTROL_POS_SAMPLE 3520 69.3331 -18.2543 -138.9397
*CONTROL_POS_SAMPLE 3680 69.1630 -17.8555 -138.9540
*CONTROL_POS_SAMPLE 3840 68.9880 -17.4450 -138.9687
*CONTROL_POS_SAMPLE 4000 68.8081 -17.0231 -138.9838
*CONTROL_POS_SAMPLE 4160 68.6235 -16.5905 -138.9993
*CONTROL_POS_SAMPLE 4320 68.4346 -16.1475 -139.0152
*CONTROL_POS_SAMPLE 4480 68.2416 -15.6947 -139.0314
*CONTROL_POS_SAMPLE 4640 68.0445 -15.2326 -139.0480
*CONTROL_POS_SAMPLE 4800 67.8437 -14.7618 -139.0648
*CONTROL_POS_SAMPLE 4960 67.6394 -14.2826 -139.0820
*CONTROL_POS_SAMPLE 5120 67.4317 -13.7956 -139.0994
*CONTROL_POS_SAMPLE 5280 67.2209 -13.3014 -139.1172
*CONTROL_POS_SAMPLE 5440 67.0073 -12.8003 -139.1351
*CONTROL_POS_SAMPLE 5600 66.7909 -12.2930 -139.1533
*CONTROL_POS_SAMPLE 5760 66.5721 -11.7799 -139.1717
*CONTROL_POS_SAMPLE 5920 66.3511 -11.2615 -139.1903
*CONTROL_POS_SAMPLE 6080 66.1280 -10.7383 -139.2090
*CONTROL_POS_SAMPLE 6240 65.9031 -10.2109 -139.2279
*CONTROL_POS_SAMPLE 6400 65.6765 -9.6797 -139.2469
*CONTROL_POS_SAMPLE 6560 65.4486 -9.1452 -139.2661
*CONTROL_POS_SAMPLE 6720 65.2195 -8.6080 -139.2854
*CONTROL_POS_SAMPLE 6880 64.9894 -8.0685 -139.3047
*CONTROL_POS_SAMPLE 7040 64.7586 -7.5272 -139.3241
*CONTROL_POS_SAMPLE 7200 64.5273 -6.9847 -139.3435
*CONTROL_POS_SAMPLE 7360 64.2956 -6.4414 -139.3630
*CONTROL_POS_SAMPLE 7520 64.0638 -5.8979 -139.3825
*CONTROL_POS_SAMPLE 7680 63.8321 -5.3546 -139.4019
*CONTROL_POS_SAMPLE 7840 63.6008 -4.8121 -139.4214
*CONTROL_POS_SAMPLE 8000 63.3700 -4.2708 -139.4408
*CONTROL_POS_SAMPLE 8160 63.1399 -3.7313 -139.4601
*CONTROL_POS_SAMPLE 8320 62.9108 -3.1941 -139.4794
*CONTROL_POS_SAMPLE 8480 62.6829 -2.6596 -139.4986
*CONTROL_POS_SAMPLE 8640 62.4564 -2.1284 -139.5176
*CONTROL_POS_SAMPLE 8800 62.2314 -1.6009 -139.5365
*CONTROL_POS_SAMPLE 8960 62.0083 -1.0778 -139.5552
*CONTROL_POS_SAMPLE 9120 61.7873 -0.5594 -139.5738
*CONTROL_POS_SAMPLE 9280 61.5685 -0.0463 -139.5922
*CONTROL_POS_SAMPLE 9440 61.3521 0.4610 -139.6103
*CONTROL_POS_SAMPLE 9600 61.1384 0.9621 -139.6283
*CONTROL_POS_SAMPLE 9760 60.9277 1.4563 -139.6460
*CONTROL_POS_SAMPLE 9920 60.7200 1.9433 -139.6635
*CONTROL_POS_SAMPLE 10080 60.5157 2.4225 -139.6807
*CONTROL_POS_SAMPLE 10240 60.3149 2.8934 -139.6975
*CONTROL_POS_SAMPLE 10400 60.1178 3.3554 -139.7141
*CONTROL_POS_SAMPLE 10560 59.9247 3.8082 -139.7303
*CONTROL_POS_SAMPLE 10720 59.7358 4.2512 -139.7462
*CONTROL_POS_SAMPLE 10880 59.5513 4.6839 -139.7617
*CONTROL_POS_SAMPLE 11040 59.3714 5.1057 -139.7768
*CONTROL_POS_SAMPLE 11200 59.1964 5.5163 -139.7915
*CONTROL_POS_SAMPLE 11360 59.0263 5.9150 -139.8058
*CONTROL_POS_SAMPLE 11520 58.8616 6.3014 -139.8196
*CONTROL_POS_SAMPLE 11680 58.7022 6.6750 -139.8330
*CONTROL_POS_SAMPLE 11840 58.5486 7.0353 -139.8459
*CONTROL_POS_SAMPLE 12000 58.4009 7.3817 -139.8583
*CONTROL_POS_SAMPLE 12160 58.2592 7.7138 -139.8703
*CONTROL_POS_SAMPLE 12320 58.1239 8.0311 -139.8816
*CONTROL_POS_SAMPLE 12480 57.9952 8.3331 -139.8925
*CONTROL_POS_SAMPLE 12640 57.8732 8.6192 -139.9027
*CONTROL_POS_SAMPLE 12800 57.7581 8.8889 -139.9124
*CONTROL_POS_SAMPLE 12960 57.6503 9.1419 -139.9214
*CONTROL_POS_SAMPLE 13120 57.5498 9.3775 -139.9299
*CONTROL_POS_SAMPLE 13280 57.4570 9.5952 -139.9377
*CONTROL_POS_SAMPLE 13440 57.3719 9.7946 -139.9448
*CONTROL_POS_SAMPLE 13600 57.2949 9.9751 -139.9513
*CONTROL_POS_SAMPLE 13760 57.2262 10.1363 -139.9570
*CONTROL_POS_SAMPLE 13920 57.1659 10.2776 -139.9621
*CONTROL_POS_SAMPLE 14080 57.1144 10.3986 -139.9665
*CONTROL_POS_SAMPLE 14240 57.0717 10.4987 -139.9700
*CONTROL_POS_SAMPLE 14400 57.0381 10.5774 -139.9729
*CONTROL_POS_SAMPLE 14560 57.0139 10.6342 -139.9749
*CONTROL_POS_SAMPLE 14720 56.9991 10.6687 -139.9761
*CONTROL_POS_SAMPLE 14880 56.9942 10.6803 -139.9766
}
}
*WIREFRAME_COLOR 0.0235 0.5294 0.0235
}

View File

@ -0,0 +1,333 @@
*3DSMAX_ASCIIEXPORT 200
*COMMENT "AsciiExport Version 2,00 - Sat Nov 08 18:02:21 2008"
*SCENE {
*SCENE_FILENAME "RotatingCube.max"
*SCENE_FIRSTFRAME 0
*SCENE_LASTFRAME 300
*SCENE_FRAMESPEED 30
*SCENE_TICKSPERFRAME 160
*SCENE_BACKGROUND_STATIC 0.0000 0.0000 0.0000
*SCENE_AMBIENT_STATIC 0.0000 0.0000 0.0000
}
*MATERIAL_LIST {
*MATERIAL_COUNT 0
}
*GEOMOBJECT {
*NODE_NAME "Box01"
*NODE_TM {
*NODE_NAME "Box01"
*INHERIT_POS 0 0 0
*INHERIT_ROT 0 0 0
*INHERIT_SCL 0 0 0
*TM_ROW0 1.0000 0.0000 0.0000
*TM_ROW1 0.0000 0.9899 -0.1420
*TM_ROW2 0.0000 0.1420 0.9899
*TM_ROW3 3.9886 -5.6980 0.0000
*TM_POS 3.9886 -5.6980 0.0000
*TM_ROTAXIS 1.0000 -0.0000 -0.0000
*TM_ROTANGLE 0.1425
*TM_SCALE 1.0000 1.0000 1.0000
*TM_SCALEAXIS 0.0000 0.0000 0.0000
*TM_SCALEAXISANG 0.0000
}
*MESH {
*TIMEVALUE 0
*MESH_NUMVERTEX 8
*MESH_NUMFACES 12
*MESH_VERTEX_LIST {
*MESH_VERTEX 0 -29.3447 -34.1813 4.0862
*MESH_VERTEX 1 37.3219 -34.1813 4.0862
*MESH_VERTEX 2 -29.3447 22.7853 -4.0862
*MESH_VERTEX 3 37.3219 22.7853 -4.0862
*MESH_VERTEX 4 -29.3447 -27.7082 49.2083
*MESH_VERTEX 5 37.3219 -27.7082 49.2083
*MESH_VERTEX 6 -29.3447 29.2585 41.0359
*MESH_VERTEX 7 37.3219 29.2585 41.0359
}
*MESH_FACE_LIST {
*MESH_FACE 0: A: 0 B: 2 C: 3 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 2 *MESH_MTLID 1
*MESH_FACE 1: A: 3 B: 1 C: 0 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 2 *MESH_MTLID 1
*MESH_FACE 2: A: 4 B: 5 C: 7 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 3 *MESH_MTLID 0
*MESH_FACE 3: A: 7 B: 6 C: 4 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 3 *MESH_MTLID 0
*MESH_FACE 4: A: 0 B: 1 C: 5 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 4 *MESH_MTLID 4
*MESH_FACE 5: A: 5 B: 4 C: 0 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 4 *MESH_MTLID 4
*MESH_FACE 6: A: 1 B: 3 C: 7 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 5 *MESH_MTLID 3
*MESH_FACE 7: A: 7 B: 5 C: 1 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 5 *MESH_MTLID 3
*MESH_FACE 8: A: 3 B: 2 C: 6 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 6 *MESH_MTLID 5
*MESH_FACE 9: A: 6 B: 7 C: 3 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 6 *MESH_MTLID 5
*MESH_FACE 10: A: 2 B: 0 C: 4 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 7 *MESH_MTLID 2
*MESH_FACE 11: A: 4 B: 6 C: 2 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 7 *MESH_MTLID 2
}
*MESH_NUMTVERTEX 12
*MESH_TVERTLIST {
*MESH_TVERT 0 0.0000 0.0000 0.0000
*MESH_TVERT 1 1.0000 0.0000 0.0000
*MESH_TVERT 2 0.0000 1.0000 0.0000
*MESH_TVERT 3 1.0000 1.0000 0.0000
*MESH_TVERT 4 0.0000 0.0000 0.0000
*MESH_TVERT 5 1.0000 0.0000 0.0000
*MESH_TVERT 6 0.0000 1.0000 0.0000
*MESH_TVERT 7 1.0000 1.0000 0.0000
*MESH_TVERT 8 0.0000 0.0000 0.0000
*MESH_TVERT 9 1.0000 0.0000 0.0000
*MESH_TVERT 10 0.0000 1.0000 0.0000
*MESH_TVERT 11 1.0000 1.0000 0.0000
}
*MESH_NUMTVFACES 12
*MESH_TFACELIST {
*MESH_TFACE 0 9 11 10
*MESH_TFACE 1 10 8 9
*MESH_TFACE 2 8 9 11
*MESH_TFACE 3 11 10 8
*MESH_TFACE 4 4 5 7
*MESH_TFACE 5 7 6 4
*MESH_TFACE 6 0 1 3
*MESH_TFACE 7 3 2 0
*MESH_TFACE 8 4 5 7
*MESH_TFACE 9 7 6 4
*MESH_TFACE 10 0 1 3
*MESH_TFACE 11 3 2 0
}
*MESH_NUMCVERTEX 0
*MESH_NORMALS {
*MESH_FACENORMAL 0 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 0 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 2 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 3 0.0000 0.0000 -1.0000
*MESH_FACENORMAL 1 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 3 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 1 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 0 0.0000 0.0000 -1.0000
*MESH_FACENORMAL 2 0.0000 -0.0000 1.0000
*MESH_VERTEXNORMAL 4 0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 5 0.0000 -0.0000 1.0000
*MESH_VERTEXNORMAL 7 0.0000 0.0000 1.0000
*MESH_FACENORMAL 3 -0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 7 0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 6 -0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 4 0.0000 0.0000 1.0000
*MESH_FACENORMAL 4 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 0 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 1 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 5 0.0000 -1.0000 0.0000
*MESH_FACENORMAL 5 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 5 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 4 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 0 0.0000 -1.0000 0.0000
*MESH_FACENORMAL 6 1.0000 0.0000 -0.0000
*MESH_VERTEXNORMAL 1 1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 3 1.0000 0.0000 -0.0000
*MESH_VERTEXNORMAL 7 1.0000 0.0000 0.0000
*MESH_FACENORMAL 7 1.0000 -0.0000 0.0000
*MESH_VERTEXNORMAL 7 1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 5 1.0000 -0.0000 0.0000
*MESH_VERTEXNORMAL 1 1.0000 0.0000 0.0000
*MESH_FACENORMAL 8 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 3 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 2 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 6 0.0000 1.0000 0.0000
*MESH_FACENORMAL 9 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 6 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 7 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 3 0.0000 1.0000 0.0000
*MESH_FACENORMAL 10 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 2 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 0 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 4 -1.0000 0.0000 0.0000
*MESH_FACENORMAL 11 -1.0000 -0.0000 -0.0000
*MESH_VERTEXNORMAL 4 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 6 -1.0000 -0.0000 -0.0000
*MESH_VERTEXNORMAL 2 -1.0000 0.0000 0.0000
}
}
*PROP_MOTIONBLUR 0
*PROP_CASTSHADOW 1
*PROP_RECVSHADOW 1
*TM_ANIMATION {
*NODE_NAME "Box01"
*CONTROL_ROT_TRACK {
*CONTROL_ROT_SAMPLE 0 1.0000 -0.0000 0.0000 0.1425
*CONTROL_ROT_SAMPLE 160 -1.0000 0.0000 0.0000 0.0008
*CONTROL_ROT_SAMPLE 320 -1.0000 0.0000 0.0000 0.0024
*CONTROL_ROT_SAMPLE 480 -1.0000 0.0000 0.0000 0.0039
*CONTROL_ROT_SAMPLE 640 -1.0000 0.0000 0.0000 0.0053
*CONTROL_ROT_SAMPLE 800 -1.0000 0.0000 0.0000 0.0067
*CONTROL_ROT_SAMPLE 960 -1.0000 0.0000 0.0000 0.0081
*CONTROL_ROT_SAMPLE 1120 -1.0000 0.0000 0.0000 0.0094
*CONTROL_ROT_SAMPLE 1280 -1.0000 0.0000 0.0000 0.0106
*CONTROL_ROT_SAMPLE 1440 -1.0000 0.0000 0.0000 0.0118
*CONTROL_ROT_SAMPLE 1600 -1.0000 0.0000 0.0000 0.0129
*CONTROL_ROT_SAMPLE 1760 -1.0000 0.0000 0.0000 0.0140
*CONTROL_ROT_SAMPLE 1920 -1.0000 0.0000 0.0000 0.0150
*CONTROL_ROT_SAMPLE 2080 -1.0000 0.0000 0.0000 0.0160
*CONTROL_ROT_SAMPLE 2240 -1.0000 0.0000 0.0000 0.0169
*CONTROL_ROT_SAMPLE 2400 -1.0000 0.0000 0.0000 0.0178
*CONTROL_ROT_SAMPLE 2560 -1.0000 0.0000 0.0000 0.0186
*CONTROL_ROT_SAMPLE 2720 -1.0000 0.0000 0.0000 0.0193
*CONTROL_ROT_SAMPLE 2880 -1.0000 0.0000 0.0000 0.0200
*CONTROL_ROT_SAMPLE 3040 -1.0000 0.0000 0.0000 0.0207
*CONTROL_ROT_SAMPLE 3200 -1.0000 0.0000 0.0000 0.0213
*CONTROL_ROT_SAMPLE 3360 -1.0000 0.0000 0.0000 0.0218
*CONTROL_ROT_SAMPLE 3520 -1.0000 0.0000 0.0000 0.0223
*CONTROL_ROT_SAMPLE 3680 -1.0000 0.0000 0.0000 0.0227
*CONTROL_ROT_SAMPLE 3840 -1.0000 0.0000 0.0000 0.0231
*CONTROL_ROT_SAMPLE 4000 -1.0000 0.0000 0.0000 0.0234
*CONTROL_ROT_SAMPLE 4160 -1.0000 0.0000 0.0000 0.0237
*CONTROL_ROT_SAMPLE 4320 -1.0000 0.0000 0.0000 0.0239
*CONTROL_ROT_SAMPLE 4480 -1.0000 0.0000 0.0000 0.0241
*CONTROL_ROT_SAMPLE 4640 -1.0000 0.0000 0.0000 0.0242
*CONTROL_ROT_SAMPLE 4800 -1.0000 0.0000 0.0000 0.0242
*CONTROL_ROT_SAMPLE 4960 -1.0000 0.0000 0.0000 0.0242
*CONTROL_ROT_SAMPLE 5120 -1.0000 0.0000 0.0000 0.0242
*CONTROL_ROT_SAMPLE 5280 -1.0000 0.0000 0.0000 0.0241
*CONTROL_ROT_SAMPLE 5440 -1.0000 0.0000 0.0000 0.0239
*CONTROL_ROT_SAMPLE 5600 -1.0000 0.0000 0.0000 0.0237
*CONTROL_ROT_SAMPLE 5760 -1.0000 0.0000 0.0000 0.0234
*CONTROL_ROT_SAMPLE 5920 -1.0000 0.0000 0.0000 0.0231
*CONTROL_ROT_SAMPLE 6080 -1.0000 0.0000 0.0000 0.0227
*CONTROL_ROT_SAMPLE 6240 -1.0000 0.0000 0.0000 0.0223
*CONTROL_ROT_SAMPLE 6400 -1.0000 0.0000 0.0000 0.0218
*CONTROL_ROT_SAMPLE 6560 -1.0000 0.0000 0.0000 0.0213
*CONTROL_ROT_SAMPLE 6720 -1.0000 0.0000 0.0000 0.0207
*CONTROL_ROT_SAMPLE 6880 -1.0000 0.0000 0.0000 0.0200
*CONTROL_ROT_SAMPLE 7040 -1.0000 0.0000 0.0000 0.0193
*CONTROL_ROT_SAMPLE 7200 -1.0000 0.0000 0.0000 0.0186
*CONTROL_ROT_SAMPLE 7360 -1.0000 0.0000 0.0000 0.0178
*CONTROL_ROT_SAMPLE 7520 -1.0000 0.0000 0.0000 0.0169
*CONTROL_ROT_SAMPLE 7680 -1.0000 0.0000 0.0000 0.0160
*CONTROL_ROT_SAMPLE 7840 -1.0000 0.0000 0.0000 0.0150
*CONTROL_ROT_SAMPLE 8000 -1.0000 0.0000 0.0000 0.0140
*CONTROL_ROT_SAMPLE 8160 -1.0000 0.0000 0.0000 0.0129
*CONTROL_ROT_SAMPLE 8320 -1.0000 0.0000 0.0000 0.0118
*CONTROL_ROT_SAMPLE 8480 -1.0000 0.0000 0.0000 0.0106
*CONTROL_ROT_SAMPLE 8640 -1.0000 0.0000 0.0000 0.0094
*CONTROL_ROT_SAMPLE 8800 -1.0000 0.0000 0.0000 0.0081
*CONTROL_ROT_SAMPLE 8960 -1.0000 0.0000 0.0000 0.0067
*CONTROL_ROT_SAMPLE 9120 -1.0000 0.0000 0.0000 0.0053
*CONTROL_ROT_SAMPLE 9280 -1.0000 0.0000 0.0000 0.0039
*CONTROL_ROT_SAMPLE 9440 -1.0000 0.0000 0.0000 0.0024
*CONTROL_ROT_SAMPLE 9600 -1.0000 0.0000 0.0000 0.0008
*CONTROL_ROT_SAMPLE 9760 0.0000 -1.0000 -0.0000 0.0012
*CONTROL_ROT_SAMPLE 9920 0.0000 -1.0000 0.0000 0.0037
*CONTROL_ROT_SAMPLE 10080 -0.0000 -1.0000 0.0000 0.0060
*CONTROL_ROT_SAMPLE 10240 -0.0000 -1.0000 0.0000 0.0083
*CONTROL_ROT_SAMPLE 10400 0.0000 -1.0000 -0.0000 0.0104
*CONTROL_ROT_SAMPLE 10560 0.0000 -1.0000 0.0000 0.0125
*CONTROL_ROT_SAMPLE 10720 -0.0000 -1.0000 0.0000 0.0145
*CONTROL_ROT_SAMPLE 10880 0.0000 -1.0000 0.0000 0.0164
*CONTROL_ROT_SAMPLE 11040 0.0000 -1.0000 -0.0000 0.0183
*CONTROL_ROT_SAMPLE 11200 0.0000 -1.0000 0.0000 0.0200
*CONTROL_ROT_SAMPLE 11360 -0.0000 -1.0000 0.0000 0.0217
*CONTROL_ROT_SAMPLE 11520 0.0000 -1.0000 -0.0000 0.0232
*CONTROL_ROT_SAMPLE 11680 -0.0000 -1.0000 0.0000 0.0247
*CONTROL_ROT_SAMPLE 11840 0.0000 -1.0000 -0.0000 0.0261
*CONTROL_ROT_SAMPLE 12000 -0.0000 -1.0000 -0.0000 0.0274
*CONTROL_ROT_SAMPLE 12160 -0.0000 -1.0000 0.0000 0.0287
*CONTROL_ROT_SAMPLE 12320 0.0000 -1.0000 -0.0000 0.0298
*CONTROL_ROT_SAMPLE 12480 -0.0000 -1.0000 0.0000 0.0309
*CONTROL_ROT_SAMPLE 12640 0.0000 -1.0000 -0.0000 0.0319
*CONTROL_ROT_SAMPLE 12800 -0.0000 -1.0000 0.0000 0.0328
*CONTROL_ROT_SAMPLE 12960 0.0000 -1.0000 -0.0000 0.0336
*CONTROL_ROT_SAMPLE 13120 -0.0000 -1.0000 0.0000 0.0343
*CONTROL_ROT_SAMPLE 13280 -0.0000 -1.0000 0.0000 0.0349
*CONTROL_ROT_SAMPLE 13440 0.0000 -1.0000 0.0000 0.0355
*CONTROL_ROT_SAMPLE 13600 -0.0000 -1.0000 -0.0000 0.0359
*CONTROL_ROT_SAMPLE 13760 0.0000 -1.0000 -0.0000 0.0363
*CONTROL_ROT_SAMPLE 13920 0.0000 -1.0000 -0.0000 0.0366
*CONTROL_ROT_SAMPLE 14080 -0.0000 -1.0000 0.0000 0.0368
*CONTROL_ROT_SAMPLE 14240 -0.0000 -1.0000 0.0000 0.0370
*CONTROL_ROT_SAMPLE 14400 0.0000 -1.0000 0.0000 0.0370
*CONTROL_ROT_SAMPLE 14560 -0.0000 -1.0000 0.0000 0.0370
*CONTROL_ROT_SAMPLE 14720 0.0000 -1.0000 -0.0000 0.0368
*CONTROL_ROT_SAMPLE 14880 -0.0000 -1.0000 0.0000 0.0366
*CONTROL_ROT_SAMPLE 15040 0.0000 -1.0000 -0.0000 0.0363
*CONTROL_ROT_SAMPLE 15200 -0.0000 -1.0000 0.0000 0.0359
*CONTROL_ROT_SAMPLE 15360 0.0000 -1.0000 0.0000 0.0355
*CONTROL_ROT_SAMPLE 15520 -0.0000 -1.0000 0.0000 0.0349
*CONTROL_ROT_SAMPLE 15680 -0.0000 -1.0000 -0.0000 0.0343
*CONTROL_ROT_SAMPLE 15840 -0.0000 -1.0000 0.0000 0.0336
*CONTROL_ROT_SAMPLE 16000 0.0000 -1.0000 0.0000 0.0328
*CONTROL_ROT_SAMPLE 16160 -0.0000 -1.0000 0.0000 0.0319
*CONTROL_ROT_SAMPLE 16320 0.0000 -1.0000 -0.0000 0.0309
*CONTROL_ROT_SAMPLE 16480 0.0000 -1.0000 0.0000 0.0298
*CONTROL_ROT_SAMPLE 16640 -0.0000 -1.0000 -0.0000 0.0287
*CONTROL_ROT_SAMPLE 16800 -0.0000 -1.0000 0.0000 0.0274
*CONTROL_ROT_SAMPLE 16960 -0.0000 -1.0000 -0.0000 0.0261
*CONTROL_ROT_SAMPLE 17120 0.0000 -1.0000 0.0000 0.0247
*CONTROL_ROT_SAMPLE 17280 -0.0000 -1.0000 -0.0000 0.0232
*CONTROL_ROT_SAMPLE 17440 0.0000 -1.0000 -0.0000 0.0217
*CONTROL_ROT_SAMPLE 17600 -0.0000 -1.0000 0.0000 0.0200
*CONTROL_ROT_SAMPLE 17760 0.0000 -1.0000 -0.0000 0.0183
*CONTROL_ROT_SAMPLE 17920 -0.0000 -1.0000 0.0000 0.0164
*CONTROL_ROT_SAMPLE 18080 0.0000 -1.0000 -0.0000 0.0145
*CONTROL_ROT_SAMPLE 18240 0.0000 -1.0000 -0.0000 0.0125
*CONTROL_ROT_SAMPLE 18400 0.0000 -1.0000 0.0000 0.0104
*CONTROL_ROT_SAMPLE 18560 -0.0000 -1.0000 0.0000 0.0083
*CONTROL_ROT_SAMPLE 18720 -0.0000 -1.0000 0.0000 0.0060
*CONTROL_ROT_SAMPLE 18880 0.0000 -1.0000 -0.0000 0.0037
*CONTROL_ROT_SAMPLE 19040 0.0000 -1.0000 0.0000 0.0012
*CONTROL_ROT_SAMPLE 19200 -0.0000 0.0000 1.0000 0.0018
*CONTROL_ROT_SAMPLE 19360 -0.0000 -0.0000 1.0000 0.0053
*CONTROL_ROT_SAMPLE 19520 0.0000 -0.0000 1.0000 0.0086
*CONTROL_ROT_SAMPLE 19680 0.0000 -0.0000 1.0000 0.0119
*CONTROL_ROT_SAMPLE 19840 0.0000 0.0000 1.0000 0.0150
*CONTROL_ROT_SAMPLE 20000 0.0000 -0.0000 1.0000 0.0180
*CONTROL_ROT_SAMPLE 20160 0.0000 0.0000 1.0000 0.0209
*CONTROL_ROT_SAMPLE 20320 0.0000 -0.0000 1.0000 0.0237
*CONTROL_ROT_SAMPLE 20480 0.0000 0.0000 1.0000 0.0263
*CONTROL_ROT_SAMPLE 20640 0.0000 -0.0000 1.0000 0.0289
*CONTROL_ROT_SAMPLE 20800 0.0000 0.0000 1.0000 0.0313
*CONTROL_ROT_SAMPLE 20960 -0.0000 -0.0000 1.0000 0.0336
*CONTROL_ROT_SAMPLE 21120 0.0000 0.0000 1.0000 0.0358
*CONTROL_ROT_SAMPLE 21280 -0.0000 0.0000 1.0000 0.0379
*CONTROL_ROT_SAMPLE 21440 0.0000 0.0000 1.0000 0.0398
*CONTROL_ROT_SAMPLE 21600 0.0000 -0.0000 1.0000 0.0416
*CONTROL_ROT_SAMPLE 21760 -0.0000 -0.0000 1.0000 0.0434
*CONTROL_ROT_SAMPLE 21920 -0.0000 0.0000 1.0000 0.0449
*CONTROL_ROT_SAMPLE 22080 0.0000 0.0000 1.0000 0.0464
*CONTROL_ROT_SAMPLE 22240 0.0000 0.0000 1.0000 0.0478
*CONTROL_ROT_SAMPLE 22400 -0.0000 0.0000 1.0000 0.0490
*CONTROL_ROT_SAMPLE 22560 -0.0000 -0.0000 1.0000 0.0501
*CONTROL_ROT_SAMPLE 22720 0.0000 0.0000 1.0000 0.0511
*CONTROL_ROT_SAMPLE 22880 -0.0000 0.0000 1.0000 0.0520
*CONTROL_ROT_SAMPLE 23040 0.0000 -0.0000 1.0000 0.0528
*CONTROL_ROT_SAMPLE 23200 -0.0000 -0.0000 1.0000 0.0535
*CONTROL_ROT_SAMPLE 23360 0.0000 0.0000 -1.0000 6.2292
*CONTROL_ROT_SAMPLE 23520 0.0000 0.0000 1.0000 0.0544
*CONTROL_ROT_SAMPLE 23680 -0.0000 0.0000 1.0000 0.0547
*CONTROL_ROT_SAMPLE 23840 0.0000 -0.0000 1.0000 0.0549
*CONTROL_ROT_SAMPLE 24000 0.0000 0.0000 1.0000 0.0549
*CONTROL_ROT_SAMPLE 24160 0.0000 -0.0000 1.0000 0.0549
*CONTROL_ROT_SAMPLE 24320 0.0000 0.0000 1.0000 0.0547
*CONTROL_ROT_SAMPLE 24480 0.0000 0.0000 1.0000 0.0544
*CONTROL_ROT_SAMPLE 24640 -0.0000 0.0000 1.0000 0.0540
*CONTROL_ROT_SAMPLE 24800 0.0000 0.0000 1.0000 0.0535
*CONTROL_ROT_SAMPLE 24960 -0.0000 -0.0000 1.0000 0.0528
*CONTROL_ROT_SAMPLE 25120 -0.0000 0.0000 1.0000 0.0520
*CONTROL_ROT_SAMPLE 25280 0.0000 0.0000 1.0000 0.0511
*CONTROL_ROT_SAMPLE 25440 -0.0000 -0.0000 1.0000 0.0501
*CONTROL_ROT_SAMPLE 25600 0.0000 0.0000 1.0000 0.0490
*CONTROL_ROT_SAMPLE 25760 -0.0000 0.0000 1.0000 0.0478
*CONTROL_ROT_SAMPLE 25920 -0.0000 -0.0000 1.0000 0.0464
*CONTROL_ROT_SAMPLE 26080 0.0000 -0.0000 1.0000 0.0449
*CONTROL_ROT_SAMPLE 26240 0.0000 0.0000 1.0000 0.0434
*CONTROL_ROT_SAMPLE 26400 0.0000 0.0000 1.0000 0.0416
*CONTROL_ROT_SAMPLE 26560 0.0000 -0.0000 1.0000 0.0398
*CONTROL_ROT_SAMPLE 26720 -0.0000 0.0000 1.0000 0.0379
*CONTROL_ROT_SAMPLE 26880 0.0000 -0.0000 1.0000 0.0358
*CONTROL_ROT_SAMPLE 27040 0.0000 0.0000 1.0000 0.0336
*CONTROL_ROT_SAMPLE 27200 0.0000 0.0000 1.0000 0.0313
*CONTROL_ROT_SAMPLE 27360 -0.0000 0.0000 1.0000 0.0289
*CONTROL_ROT_SAMPLE 27520 -0.0000 0.0000 1.0000 0.0263
*CONTROL_ROT_SAMPLE 27680 0.0000 -0.0000 1.0000 0.0237
*CONTROL_ROT_SAMPLE 27840 -0.0000 0.0000 1.0000 0.0209
*CONTROL_ROT_SAMPLE 28000 0.0000 -0.0000 1.0000 0.0180
*CONTROL_ROT_SAMPLE 28160 -0.0000 0.0000 1.0000 0.0150
*CONTROL_ROT_SAMPLE 28320 0.0000 -0.0000 1.0000 0.0119
*CONTROL_ROT_SAMPLE 28480 0.0000 0.0000 1.0000 0.0086
*CONTROL_ROT_SAMPLE 28640 -0.0000 -0.0000 1.0000 0.0053
*CONTROL_ROT_SAMPLE 28800 0.0000 -0.0001 1.0000 0.0018
}
}
*WIREFRAME_COLOR 0.2235 0.0314 0.5333
}

View File

@ -0,0 +1,385 @@
*3DSMAX_ASCIIEXPORT 200
*COMMENT "AsciiExport Version 2,00 - Sat Nov 08 16:24:29 2008"
*SCENE {
*SCENE_FILENAME "TargetCameraAnim.max"
*SCENE_FIRSTFRAME 0
*SCENE_LASTFRAME 300
*SCENE_FRAMESPEED 30
*SCENE_TICKSPERFRAME 160
*SCENE_BACKGROUND_STATIC 0.0000 0.0000 0.0000
*SCENE_AMBIENT_STATIC 0.0000 0.0000 0.0000
}
*MATERIAL_LIST {
*MATERIAL_COUNT 0
}
*GEOMOBJECT {
*NODE_NAME "Box01"
*NODE_TM {
*NODE_NAME "Box01"
*INHERIT_POS 0 0 0
*INHERIT_ROT 0 0 0
*INHERIT_SCL 0 0 0
*TM_ROW0 1.0000 0.0000 0.0000
*TM_ROW1 0.0000 1.0000 0.0000
*TM_ROW2 0.0000 0.0000 1.0000
*TM_ROW3 10.5413 -0.8547 0.0000
*TM_POS 10.5413 -0.8547 0.0000
*TM_ROTAXIS 0.0000 0.0000 0.0000
*TM_ROTANGLE 0.0000
*TM_SCALE 1.0000 1.0000 1.0000
*TM_SCALEAXIS 0.0000 0.0000 0.0000
*TM_SCALEAXISANG 0.0000
}
*MESH {
*TIMEVALUE 0
*MESH_NUMVERTEX 8
*MESH_NUMFACES 12
*MESH_VERTEX_LIST {
*MESH_VERTEX 0 -24.7863 -24.7863 0.0000
*MESH_VERTEX 1 45.8689 -24.7863 0.0000
*MESH_VERTEX 2 -24.7863 23.0769 0.0000
*MESH_VERTEX 3 45.8689 23.0769 0.0000
*MESH_VERTEX 4 -24.7863 -24.7863 38.7464
*MESH_VERTEX 5 45.8689 -24.7863 38.7464
*MESH_VERTEX 6 -24.7863 23.0769 38.7464
*MESH_VERTEX 7 45.8689 23.0769 38.7464
}
*MESH_FACE_LIST {
*MESH_FACE 0: A: 0 B: 2 C: 3 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 2 *MESH_MTLID 1
*MESH_FACE 1: A: 3 B: 1 C: 0 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 2 *MESH_MTLID 1
*MESH_FACE 2: A: 4 B: 5 C: 7 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 3 *MESH_MTLID 0
*MESH_FACE 3: A: 7 B: 6 C: 4 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 3 *MESH_MTLID 0
*MESH_FACE 4: A: 0 B: 1 C: 5 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 4 *MESH_MTLID 4
*MESH_FACE 5: A: 5 B: 4 C: 0 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 4 *MESH_MTLID 4
*MESH_FACE 6: A: 1 B: 3 C: 7 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 5 *MESH_MTLID 3
*MESH_FACE 7: A: 7 B: 5 C: 1 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 5 *MESH_MTLID 3
*MESH_FACE 8: A: 3 B: 2 C: 6 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 6 *MESH_MTLID 5
*MESH_FACE 9: A: 6 B: 7 C: 3 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 6 *MESH_MTLID 5
*MESH_FACE 10: A: 2 B: 0 C: 4 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 7 *MESH_MTLID 2
*MESH_FACE 11: A: 4 B: 6 C: 2 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING 7 *MESH_MTLID 2
}
*MESH_NUMTVERTEX 12
*MESH_TVERTLIST {
*MESH_TVERT 0 0.0000 0.0000 0.0000
*MESH_TVERT 1 1.0000 0.0000 0.0000
*MESH_TVERT 2 0.0000 1.0000 0.0000
*MESH_TVERT 3 1.0000 1.0000 0.0000
*MESH_TVERT 4 0.0000 0.0000 0.0000
*MESH_TVERT 5 1.0000 0.0000 0.0000
*MESH_TVERT 6 0.0000 1.0000 0.0000
*MESH_TVERT 7 1.0000 1.0000 0.0000
*MESH_TVERT 8 0.0000 0.0000 0.0000
*MESH_TVERT 9 1.0000 0.0000 0.0000
*MESH_TVERT 10 0.0000 1.0000 0.0000
*MESH_TVERT 11 1.0000 1.0000 0.0000
}
*MESH_NUMTVFACES 12
*MESH_TFACELIST {
*MESH_TFACE 0 9 11 10
*MESH_TFACE 1 10 8 9
*MESH_TFACE 2 8 9 11
*MESH_TFACE 3 11 10 8
*MESH_TFACE 4 4 5 7
*MESH_TFACE 5 7 6 4
*MESH_TFACE 6 0 1 3
*MESH_TFACE 7 3 2 0
*MESH_TFACE 8 4 5 7
*MESH_TFACE 9 7 6 4
*MESH_TFACE 10 0 1 3
*MESH_TFACE 11 3 2 0
}
*MESH_NUMCVERTEX 0
*MESH_NORMALS {
*MESH_FACENORMAL 0 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 0 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 2 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 3 0.0000 0.0000 -1.0000
*MESH_FACENORMAL 1 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 3 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 1 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 0 0.0000 0.0000 -1.0000
*MESH_FACENORMAL 2 0.0000 -0.0000 1.0000
*MESH_VERTEXNORMAL 4 0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 5 0.0000 -0.0000 1.0000
*MESH_VERTEXNORMAL 7 0.0000 0.0000 1.0000
*MESH_FACENORMAL 3 -0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 7 0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 6 -0.0000 0.0000 1.0000
*MESH_VERTEXNORMAL 4 0.0000 0.0000 1.0000
*MESH_FACENORMAL 4 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 0 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 1 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 5 0.0000 -1.0000 0.0000
*MESH_FACENORMAL 5 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 5 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 4 0.0000 -1.0000 0.0000
*MESH_VERTEXNORMAL 0 0.0000 -1.0000 0.0000
*MESH_FACENORMAL 6 1.0000 0.0000 -0.0000
*MESH_VERTEXNORMAL 1 1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 3 1.0000 0.0000 -0.0000
*MESH_VERTEXNORMAL 7 1.0000 0.0000 0.0000
*MESH_FACENORMAL 7 1.0000 -0.0000 0.0000
*MESH_VERTEXNORMAL 7 1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 5 1.0000 -0.0000 0.0000
*MESH_VERTEXNORMAL 1 1.0000 0.0000 0.0000
*MESH_FACENORMAL 8 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 3 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 2 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 6 0.0000 1.0000 0.0000
*MESH_FACENORMAL 9 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 6 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 7 0.0000 1.0000 0.0000
*MESH_VERTEXNORMAL 3 0.0000 1.0000 0.0000
*MESH_FACENORMAL 10 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 2 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 0 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 4 -1.0000 0.0000 0.0000
*MESH_FACENORMAL 11 -1.0000 -0.0000 -0.0000
*MESH_VERTEXNORMAL 4 -1.0000 0.0000 0.0000
*MESH_VERTEXNORMAL 6 -1.0000 -0.0000 -0.0000
*MESH_VERTEXNORMAL 2 -1.0000 0.0000 0.0000
}
}
*PROP_MOTIONBLUR 0
*PROP_CASTSHADOW 1
*PROP_RECVSHADOW 1
*WIREFRAME_COLOR 0.6941 0.3451 0.1059
}
*CAMERAOBJECT {
*NODE_NAME "Camera01"
*CAMERA_TYPE Target
*NODE_TM {
*NODE_NAME "Camera01"
*INHERIT_POS 0 0 0
*INHERIT_ROT 0 0 0
*INHERIT_SCL 1 1 1
*TM_ROW0 0.1489 -0.9888 0.0000
*TM_ROW1 0.0000 0.0000 1.0000
*TM_ROW2 -0.9888 -0.1489 0.0000
*TM_ROW3 -65.8677 16.1213 0.0000
*TM_POS -65.8677 16.1213 0.0000
*TM_ROTAXIS -0.6348 0.5464 0.5464
*TM_ROTANGLE 2.0103
*TM_SCALE 1.0000 1.0000 1.0000
*TM_SCALEAXIS 0.0000 0.0000 0.0000
*TM_SCALEAXISANG 0.0000
}
*NODE_TM {
*NODE_NAME "Camera01.Target"
*INHERIT_POS 0 0 0
*INHERIT_ROT 0 0 0
*INHERIT_SCL 0 0 0
*TM_ROW0 1.0000 0.0000 0.0000
*TM_ROW1 0.0000 1.0000 0.0000
*TM_ROW2 0.0000 0.0000 1.0000
*TM_ROW3 14.4292 28.2159 0.0000
*TM_POS 14.4292 28.2159 0.0000
*TM_ROTAXIS 0.0000 0.0000 0.0000
*TM_ROTANGLE 0.0000
*TM_SCALE 1.0000 1.0000 1.0000
*TM_SCALEAXIS 0.0000 0.0000 0.0000
*TM_SCALEAXISANG 0.0000
}
*CAMERA_SETTINGS {
*TIMEVALUE 0
*CAMERA_NEAR 0.0000
*CAMERA_FAR 1000.0000
*CAMERA_FOV 0.7854
*CAMERA_TDIST 166.7347
}
*TM_ANIMATION {
*NODE_NAME "Camera01"
*CONTROL_POS_TRACK {
*CONTROL_POS_SAMPLE 0 -65.8677 16.1213 0.0000
*CONTROL_POS_SAMPLE 160 -65.8677 16.1213 0.2784
*CONTROL_POS_SAMPLE 320 -65.8677 16.1213 1.0883
*CONTROL_POS_SAMPLE 480 -65.8677 16.1213 2.3917
*CONTROL_POS_SAMPLE 640 -65.8677 16.1213 4.1507
*CONTROL_POS_SAMPLE 800 -65.8677 16.1213 6.3273
*CONTROL_POS_SAMPLE 960 -65.8677 16.1213 8.8835
*CONTROL_POS_SAMPLE 1120 -65.8677 16.1213 11.7814
*CONTROL_POS_SAMPLE 1280 -65.8677 16.1213 14.9830
*CONTROL_POS_SAMPLE 1440 -65.8677 16.1213 18.4503
*CONTROL_POS_SAMPLE 1600 -65.8677 16.1213 22.1454
*CONTROL_POS_SAMPLE 1760 -65.8677 16.1213 26.0304
*CONTROL_POS_SAMPLE 1920 -65.8677 16.1213 30.0672
*CONTROL_POS_SAMPLE 2080 -65.8677 16.1213 34.2179
*CONTROL_POS_SAMPLE 2240 -65.8677 16.1213 38.4445
*CONTROL_POS_SAMPLE 2400 -65.8677 16.1213 42.7091
*CONTROL_POS_SAMPLE 2560 -65.8677 16.1213 46.9737
*CONTROL_POS_SAMPLE 2720 -65.8677 16.1213 51.2003
*CONTROL_POS_SAMPLE 2880 -65.8677 16.1213 55.3510
*CONTROL_POS_SAMPLE 3040 -65.8677 16.1213 59.3877
*CONTROL_POS_SAMPLE 3200 -65.8677 16.1213 63.2727
*CONTROL_POS_SAMPLE 3360 -65.8677 16.1213 66.9678
*CONTROL_POS_SAMPLE 3520 -65.8677 16.1213 70.4352
*CONTROL_POS_SAMPLE 3680 -65.8677 16.1213 73.6368
*CONTROL_POS_SAMPLE 3840 -65.8677 16.1213 76.5347
*CONTROL_POS_SAMPLE 4000 -65.8677 16.1213 79.0909
*CONTROL_POS_SAMPLE 4160 -65.8677 16.1213 81.2674
*CONTROL_POS_SAMPLE 4320 -65.8677 16.1213 83.0264
*CONTROL_POS_SAMPLE 4480 -65.8677 16.1213 84.3298
*CONTROL_POS_SAMPLE 4640 -65.8677 16.1213 85.1397
*CONTROL_POS_SAMPLE 4800 -65.8677 16.1213 85.4181
*CONTROL_POS_SAMPLE 9760 -65.8677 16.1213 84.8455
*CONTROL_POS_SAMPLE 9920 -65.8677 16.1213 83.1798
*CONTROL_POS_SAMPLE 10080 -65.8677 16.1213 80.4989
*CONTROL_POS_SAMPLE 10240 -65.8677 16.1213 76.8811
*CONTROL_POS_SAMPLE 10400 -65.8677 16.1213 72.4043
*CONTROL_POS_SAMPLE 10560 -65.8677 16.1213 67.1468
*CONTROL_POS_SAMPLE 10720 -65.8677 16.1213 61.1864
*CONTROL_POS_SAMPLE 10880 -65.8677 16.1213 54.6015
*CONTROL_POS_SAMPLE 11040 -65.8677 16.1213 47.4699
*CONTROL_POS_SAMPLE 11200 -65.8677 16.1213 39.8698
*CONTROL_POS_SAMPLE 11360 -65.8677 16.1213 31.8794
*CONTROL_POS_SAMPLE 11520 -65.8677 16.1213 23.5766
*CONTROL_POS_SAMPLE 11680 -65.8677 16.1213 15.0395
*CONTROL_POS_SAMPLE 11840 -65.8677 16.1213 6.3463
*CONTROL_POS_SAMPLE 12000 -65.8677 16.1213 -2.4250
*CONTROL_POS_SAMPLE 12160 -65.8677 16.1213 -11.1963
*CONTROL_POS_SAMPLE 12320 -65.8677 16.1213 -19.8895
*CONTROL_POS_SAMPLE 12480 -65.8677 16.1213 -28.4266
*CONTROL_POS_SAMPLE 12640 -65.8677 16.1213 -36.7294
*CONTROL_POS_SAMPLE 12800 -65.8677 16.1213 -44.7199
*CONTROL_POS_SAMPLE 12960 -65.8677 16.1213 -52.3199
*CONTROL_POS_SAMPLE 13120 -65.8677 16.1213 -59.4515
*CONTROL_POS_SAMPLE 13280 -65.8677 16.1213 -66.0365
*CONTROL_POS_SAMPLE 13440 -65.8677 16.1213 -71.9968
*CONTROL_POS_SAMPLE 13600 -65.8677 16.1213 -77.2544
*CONTROL_POS_SAMPLE 13760 -65.8677 16.1213 -81.7311
*CONTROL_POS_SAMPLE 13920 -65.8677 16.1213 -85.3490
*CONTROL_POS_SAMPLE 14080 -65.8677 16.1213 -88.0298
*CONTROL_POS_SAMPLE 14240 -65.8677 16.1213 -89.6956
*CONTROL_POS_SAMPLE 14400 -65.8677 16.1213 -90.2682
}
*CONTROL_ROT_TRACK {
*CONTROL_ROT_SAMPLE 0 -0.6348 0.5464 0.5464 2.0103
*CONTROL_ROT_SAMPLE 160 0.1489 -0.9888 0.0000 0.0034
*CONTROL_ROT_SAMPLE 320 0.1490 -0.9888 -0.0000 0.0100
*CONTROL_ROT_SAMPLE 480 0.1489 -0.9888 0.0000 0.0160
*CONTROL_ROT_SAMPLE 640 0.1489 -0.9888 -0.0000 0.0216
*CONTROL_ROT_SAMPLE 800 0.1489 -0.9888 0.0000 0.0267
*CONTROL_ROT_SAMPLE 960 0.1489 -0.9888 -0.0000 0.0312
*CONTROL_ROT_SAMPLE 1120 0.1489 -0.9888 0.0000 0.0351
*CONTROL_ROT_SAMPLE 1280 0.1489 -0.9888 0.0000 0.0384
*CONTROL_ROT_SAMPLE 1440 0.1489 -0.9888 0.0000 0.0410
*CONTROL_ROT_SAMPLE 1600 0.1489 -0.9888 0.0000 0.0428
*CONTROL_ROT_SAMPLE 1760 0.1489 -0.9888 -0.0000 0.0440
*CONTROL_ROT_SAMPLE 1920 0.1489 -0.9888 0.0000 0.0444
*CONTROL_ROT_SAMPLE 2080 0.1489 -0.9888 -0.0000 0.0442
*CONTROL_ROT_SAMPLE 2240 0.1489 -0.9888 -0.0000 0.0434
*CONTROL_ROT_SAMPLE 2400 0.1489 -0.9888 0.0000 0.0420
*CONTROL_ROT_SAMPLE 2560 0.1489 -0.9888 0.0000 0.0402
*CONTROL_ROT_SAMPLE 2720 0.1489 -0.9888 -0.0000 0.0381
*CONTROL_ROT_SAMPLE 2880 0.1489 -0.9888 0.0000 0.0357
*CONTROL_ROT_SAMPLE 3040 0.1489 -0.9888 -0.0000 0.0332
*CONTROL_ROT_SAMPLE 3200 0.1489 -0.9888 -0.0000 0.0305
*CONTROL_ROT_SAMPLE 3360 0.1489 -0.9888 0.0000 0.0277
*CONTROL_ROT_SAMPLE 3520 0.1489 -0.9888 -0.0000 0.0249
*CONTROL_ROT_SAMPLE 3680 0.1489 -0.9888 0.0000 0.0221
*CONTROL_ROT_SAMPLE 3840 0.1489 -0.9888 -0.0000 0.0192
*CONTROL_ROT_SAMPLE 4000 0.1489 -0.9888 0.0000 0.0164
*CONTROL_ROT_SAMPLE 4160 0.1489 -0.9888 0.0000 0.0136
*CONTROL_ROT_SAMPLE 4320 0.1489 -0.9888 -0.0000 0.0107
*CONTROL_ROT_SAMPLE 4480 0.1489 -0.9888 -0.0000 0.0078
*CONTROL_ROT_SAMPLE 4640 0.1489 -0.9888 0.0000 0.0048
*CONTROL_ROT_SAMPLE 4800 0.1489 -0.9888 0.0000 0.0016
*CONTROL_ROT_SAMPLE 4960 -0.1424 0.9469 0.2882 0.0018
*CONTROL_ROT_SAMPLE 5120 -0.1415 0.9476 0.2864 0.0051
*CONTROL_ROT_SAMPLE 5280 -0.1399 0.9489 0.2829 0.0082
*CONTROL_ROT_SAMPLE 5440 -0.1376 0.9507 0.2780 0.0108
*CONTROL_ROT_SAMPLE 5600 -0.1347 0.9528 0.2721 0.0130
*CONTROL_ROT_SAMPLE 5760 -0.1314 0.9551 0.2654 0.0149
*CONTROL_ROT_SAMPLE 5920 -0.1277 0.9576 0.2583 0.0163
*CONTROL_ROT_SAMPLE 6080 -0.1239 0.9600 0.2511 0.0174
*CONTROL_ROT_SAMPLE 6240 -0.1199 0.9624 0.2438 0.0181
*CONTROL_ROT_SAMPLE 6400 -0.1159 0.9646 0.2368 0.0185
*CONTROL_ROT_SAMPLE 6560 -0.1119 0.9667 0.2301 0.0186
*CONTROL_ROT_SAMPLE 6720 -0.1080 0.9686 0.2239 0.0184
*CONTROL_ROT_SAMPLE 6880 -0.1042 0.9704 0.2180 0.0181
*CONTROL_ROT_SAMPLE 7040 -0.1006 0.9719 0.2127 0.0175
*CONTROL_ROT_SAMPLE 7200 -0.0972 0.9733 0.2077 0.0169
*CONTROL_ROT_SAMPLE 7360 -0.0940 0.9746 0.2033 0.0161
*CONTROL_ROT_SAMPLE 7520 -0.0910 0.9757 0.1993 0.0152
*CONTROL_ROT_SAMPLE 7680 -0.0882 0.9767 0.1957 0.0143
*CONTROL_ROT_SAMPLE 7840 -0.0857 0.9776 0.1925 0.0133
*CONTROL_ROT_SAMPLE 8000 -0.0833 0.9783 0.1896 0.0123
*CONTROL_ROT_SAMPLE 8160 -0.0812 0.9790 0.1871 0.0112
*CONTROL_ROT_SAMPLE 8320 -0.0793 0.9795 0.1849 0.0102
*CONTROL_ROT_SAMPLE 8480 -0.0776 0.9800 0.1830 0.0091
*CONTROL_ROT_SAMPLE 8640 -0.0761 0.9805 0.1814 0.0080
*CONTROL_ROT_SAMPLE 8800 -0.0748 0.9808 0.1800 0.0068
*CONTROL_ROT_SAMPLE 8960 -0.0737 0.9811 0.1788 0.0057
*CONTROL_ROT_SAMPLE 9120 -0.0728 0.9814 0.1779 0.0045
*CONTROL_ROT_SAMPLE 9280 -0.0721 0.9815 0.1772 0.0033
*CONTROL_ROT_SAMPLE 9440 -0.0717 0.9816 0.1767 0.0020
*CONTROL_ROT_SAMPLE 9600 -0.0714 0.9817 0.1765 0.0007
*CONTROL_ROT_SAMPLE 9760 -0.0725 0.9974 -0.0000 0.0027
*CONTROL_ROT_SAMPLE 9920 -0.0726 0.9974 0.0000 0.0080
*CONTROL_ROT_SAMPLE 10080 -0.0725 0.9974 0.0000 0.0130
*CONTROL_ROT_SAMPLE 10240 -0.0725 0.9974 -0.0000 0.0177
*CONTROL_ROT_SAMPLE 10400 -0.0725 0.9974 0.0000 0.0224
*CONTROL_ROT_SAMPLE 10560 -0.0725 0.9974 0.0000 0.0268
*CONTROL_ROT_SAMPLE 10720 -0.0725 0.9974 -0.0000 0.0311
*CONTROL_ROT_SAMPLE 10880 -0.0725 0.9974 0.0000 0.0352
*CONTROL_ROT_SAMPLE 11040 -0.0725 0.9974 -0.0000 0.0391
*CONTROL_ROT_SAMPLE 11200 -0.0725 0.9974 0.0000 0.0427
*CONTROL_ROT_SAMPLE 11360 -0.0725 0.9974 -0.0000 0.0458
*CONTROL_ROT_SAMPLE 11520 -0.0725 0.9974 0.0000 0.0485
*CONTROL_ROT_SAMPLE 11680 -0.0725 0.9974 -0.0000 0.0505
*CONTROL_ROT_SAMPLE 11840 -0.0725 0.9974 -0.0000 0.0519
*CONTROL_ROT_SAMPLE 12000 -0.0725 0.9974 0.0000 0.0526
*CONTROL_ROT_SAMPLE 12160 -0.0725 0.9974 -0.0000 0.0525
*CONTROL_ROT_SAMPLE 12320 -0.0725 0.9974 0.0000 0.0517
*CONTROL_ROT_SAMPLE 12480 -0.0725 0.9974 -0.0000 0.0501
*CONTROL_ROT_SAMPLE 12640 -0.0725 0.9974 -0.0000 0.0480
*CONTROL_ROT_SAMPLE 12800 -0.0725 0.9974 0.0000 0.0452
*CONTROL_ROT_SAMPLE 12960 -0.0725 0.9974 -0.0000 0.0420
*CONTROL_ROT_SAMPLE 13120 -0.0725 0.9974 -0.0000 0.0385
*CONTROL_ROT_SAMPLE 13280 -0.0725 0.9974 0.0000 0.0346
*CONTROL_ROT_SAMPLE 13440 -0.0725 0.9974 0.0000 0.0305
*CONTROL_ROT_SAMPLE 13600 -0.0725 0.9974 -0.0000 0.0263
*CONTROL_ROT_SAMPLE 13760 -0.0725 0.9974 -0.0000 0.0219
*CONTROL_ROT_SAMPLE 13920 -0.0725 0.9974 0.0000 0.0173
*CONTROL_ROT_SAMPLE 14080 -0.0725 0.9974 0.0000 0.0127
*CONTROL_ROT_SAMPLE 14240 -0.0726 0.9974 0.0000 0.0078
*CONTROL_ROT_SAMPLE 14400 -0.0725 0.9974 0.0000 0.0027
}
}
*TM_ANIMATION {
*NODE_NAME "Camera01.Target"
*CONTROL_POS_TRACK {
*CONTROL_POS_SAMPLE 0 14.4292 28.2159 0.0000
*CONTROL_POS_SAMPLE 4960 14.7094 28.2159 0.0000
*CONTROL_POS_SAMPLE 5120 15.5247 28.2159 0.0000
*CONTROL_POS_SAMPLE 5280 16.8367 28.2159 0.0000
*CONTROL_POS_SAMPLE 5440 18.6072 28.2159 0.0000
*CONTROL_POS_SAMPLE 5600 20.7982 28.2159 0.0000
*CONTROL_POS_SAMPLE 5760 23.3712 28.2159 0.0000
*CONTROL_POS_SAMPLE 5920 26.2882 28.2159 0.0000
*CONTROL_POS_SAMPLE 6080 29.5109 28.2159 0.0000
*CONTROL_POS_SAMPLE 6240 33.0011 28.2159 0.0000
*CONTROL_POS_SAMPLE 6400 36.7205 28.2159 0.0000
*CONTROL_POS_SAMPLE 6560 40.6311 28.2159 0.0000
*CONTROL_POS_SAMPLE 6720 44.6945 28.2159 0.0000
*CONTROL_POS_SAMPLE 6880 48.8725 28.2159 0.0000
*CONTROL_POS_SAMPLE 7040 53.1270 28.2159 0.0000
*CONTROL_POS_SAMPLE 7200 57.4196 28.2159 0.0000
*CONTROL_POS_SAMPLE 7360 61.7123 28.2159 0.0000
*CONTROL_POS_SAMPLE 7520 65.9668 28.2159 0.0000
*CONTROL_POS_SAMPLE 7680 70.1448 28.2159 0.0000
*CONTROL_POS_SAMPLE 7840 74.2082 28.2159 0.0000
*CONTROL_POS_SAMPLE 8000 78.1187 28.2159 0.0000
*CONTROL_POS_SAMPLE 8160 81.8382 28.2159 0.0000
*CONTROL_POS_SAMPLE 8320 85.3284 28.2159 0.0000
*CONTROL_POS_SAMPLE 8480 88.5511 28.2159 0.0000
*CONTROL_POS_SAMPLE 8640 91.4680 28.2159 0.0000
*CONTROL_POS_SAMPLE 8800 94.0411 28.2159 0.0000
*CONTROL_POS_SAMPLE 8960 96.2320 28.2159 0.0000
*CONTROL_POS_SAMPLE 9120 98.0026 28.2159 0.0000
*CONTROL_POS_SAMPLE 9280 99.3146 28.2159 0.0000
*CONTROL_POS_SAMPLE 9440 100.1298 28.2159 0.0000
*CONTROL_POS_SAMPLE 9600 100.4100 28.2159 0.0000
}
}
}

View File

@ -1,2 +1,6 @@
"würfel.ase" - Made by Marius Schröder, free for any purpose "würfel.ase" - Made by Marius Schröder, free for any purpose
"MotionCaptureROM.ase" - Recorded at the HTW Aalen using LycosIQ. Free for any purpose
"MotionCaptureROM.ase" - Recorded at the HTW Aalen using LycosIQ.
NOTE: The errors in the middle of the animation are there in the
original animation track, too. The captured person lost a sensor ...

Binary file not shown.

BIN
test/IRR/skybox.xml 100644

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -895,6 +895,14 @@
RelativePath="..\..\code\StringComparison.h" RelativePath="..\..\code\StringComparison.h"
> >
</File> </File>
<File
RelativePath="..\..\code\TargetAnimation.cpp"
>
</File>
<File
RelativePath="..\..\code\TargetAnimation.h"
>
</File>
<File <File
RelativePath="..\..\code\TextureTransform.cpp" RelativePath="..\..\code\TextureTransform.cpp"
> >