diff --git a/code/SkeletonMeshBuilder.cpp b/code/SkeletonMeshBuilder.cpp index 188419481..87473e287 100644 --- a/code/SkeletonMeshBuilder.cpp +++ b/code/SkeletonMeshBuilder.cpp @@ -90,8 +90,8 @@ void SkeletonMeshBuilder::CreateGeometry( const aiNode* pNode) const aiMatrix4x4& childTransform = pNode->mChildren[a]->mTransformation; aiVector3D childpos( childTransform.a4, childTransform.b4, childTransform.c4); float distanceToChild = childpos.Length(); - if( distanceToChild < 0.0001f) - continue; + if( distanceToChild < 0.0001f) + continue; aiVector3D up = aiVector3D( childpos).Normalize(); aiVector3D orth( 1.0f, 0.0f, 0.0f); @@ -163,34 +163,34 @@ void SkeletonMeshBuilder::CreateGeometry( const aiNode* pNode) } unsigned int numVertices = mVertices.size() - vertexStartIndex; - if( numVertices > 0) - { - // create a bone affecting all the newly created vertices - aiBone* bone = new aiBone; - mBones.push_back( bone); - bone->mName = pNode->mName; + if( numVertices > 0) + { + // create a bone affecting all the newly created vertices + aiBone* bone = new aiBone; + mBones.push_back( bone); + bone->mName = pNode->mName; - // calculate the bone offset matrix by concatenating the inverse transformations of all parents - bone->mOffsetMatrix = aiMatrix4x4( pNode->mTransformation).Inverse(); - for( aiNode* parent = pNode->mParent; parent != NULL; parent = parent->mParent) - bone->mOffsetMatrix = aiMatrix4x4( parent->mTransformation).Inverse() * bone->mOffsetMatrix; + // calculate the bone offset matrix by concatenating the inverse transformations of all parents + bone->mOffsetMatrix = aiMatrix4x4( pNode->mTransformation).Inverse(); + for( aiNode* parent = pNode->mParent; parent != NULL; parent = parent->mParent) + bone->mOffsetMatrix = aiMatrix4x4( parent->mTransformation).Inverse() * bone->mOffsetMatrix; - // add all the vertices to the bone's influences - bone->mNumWeights = numVertices; - bone->mWeights = new aiVertexWeight[numVertices]; - for( unsigned int a = 0; a < numVertices; a++) - bone->mWeights[a] = aiVertexWeight( vertexStartIndex + a, 1.0f); + // add all the vertices to the bone's influences + bone->mNumWeights = numVertices; + bone->mWeights = new aiVertexWeight[numVertices]; + for( unsigned int a = 0; a < numVertices; a++) + bone->mWeights[a] = aiVertexWeight( vertexStartIndex + a, 1.0f); - // HACK: (thom) transform all vertices to the bone's local space. Should be done before adding - // them to the array, but I'm tired now and I'm annoyed. - aiMatrix4x4 boneToMeshTransform = aiMatrix4x4( bone->mOffsetMatrix).Inverse(); - for( unsigned int a = vertexStartIndex; a < mVertices.size(); a++) - mVertices[a] = boneToMeshTransform * mVertices[a]; - } + // HACK: (thom) transform all vertices to the bone's local space. Should be done before adding + // them to the array, but I'm tired now and I'm annoyed. + aiMatrix4x4 boneToMeshTransform = aiMatrix4x4( bone->mOffsetMatrix).Inverse(); + for( unsigned int a = vertexStartIndex; a < mVertices.size(); a++) + mVertices[a] = boneToMeshTransform * mVertices[a]; + } - // and finally recurse into the children list - for( unsigned int a = 0; a < pNode->mNumChildren; a++) - CreateGeometry( pNode->mChildren[a]); + // and finally recurse into the children list + for( unsigned int a = 0; a < pNode->mNumChildren; a++) + CreateGeometry( pNode->mChildren[a]); } // ------------------------------------------------------------------------------------------------ diff --git a/tools/assimp_view/AnimEvaluator.h b/tools/assimp_view/AnimEvaluator.h index fc150b0b0..fbe7fbdc2 100644 --- a/tools/assimp_view/AnimEvaluator.h +++ b/tools/assimp_view/AnimEvaluator.h @@ -48,6 +48,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace AssimpView { +/** Calculates transformations for a given timestamp from a set of animation tracks. Not directly useful, + * better use the AnimPlayer class. + */ class AnimEvaluator { public: diff --git a/tools/assimp_view/AssetHelper.h b/tools/assimp_view/AssetHelper.h index ee53a0eb4..91041a51a 100644 --- a/tools/assimp_view/AssetHelper.h +++ b/tools/assimp_view/AssetHelper.h @@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if (!defined AV_ASSET_HELPER_H_INCLUDED) #define AV_ASSET_HELPER_H_INCLUDED +class SceneAnimator; //------------------------------------------------------------------------------- /** \brief Class to wrap ASSIMP's asset output structures @@ -66,7 +67,11 @@ class AssetHelper // default constructor AssetHelper() : iNormalSet(ORIGINAL) - {} + { + mAnimator = NULL; + apcMeshes = NULL; + pcScene = NULL; + } //--------------------------------------------------------------- // default vertex data structure @@ -74,7 +79,7 @@ class AssetHelper // required by the shader they will be committed to the GPU) //--------------------------------------------------------------- struct Vertex - { + { aiVector3D vPosition; aiVector3D vNormal; @@ -82,30 +87,43 @@ class AssetHelper aiVector3D vTangent; aiVector3D vBitangent; aiVector2D vTextureUV; + unsigned char mBoneIndices[4]; + unsigned char mBoneWeights[4]; // last Weight not used, calculated inside the vertex shader - // retrieves the FVF code of the vertex type - static DWORD GetFVF() + /** Returns the vertex declaration elements to create a declaration from. */ + static D3DVERTEXELEMENT9* GetDeclarationElements() + { + static D3DVERTEXELEMENT9 decl[] = { - return D3DFVF_DIFFUSE | D3DFVF_XYZ | D3DFVF_NORMAL | - D3DFVF_TEX1 | D3DFVF_TEX2 | D3DFVF_TEX3 | - D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEXCOORDSIZE3(1); - } - }; + { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }, + { 0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, + { 0, 28, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0 }, + { 0, 40, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0 }, + { 0, 52, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, + { 0, 60, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDINDICES, 0 }, + { 0, 64, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0 }, + D3DDECL_END() + }; + + return decl; + } + }; //--------------------------------------------------------------- // FVF vertex structure used for normals //--------------------------------------------------------------- struct LineVertex - { + { aiVector3D vPosition; DWORD dColorDiffuse; // retrieves the FVF code of the vertex type static DWORD GetFVF() - { + { return D3DFVF_DIFFUSE | D3DFVF_XYZ; - } - }; + } + }; //--------------------------------------------------------------- // Helper class to store GPU related resources created for @@ -191,6 +209,9 @@ class AssetHelper // Scene wrapper instance aiScene* pcScene; + // Animation player to animate the scene if necessary + SceneAnimator* mAnimator; + // Specifies the normal set to be used unsigned int iNormalSet; diff --git a/tools/assimp_view/Material.cpp b/tools/assimp_view/Material.cpp index d323d10b6..d8ce11936 100644 --- a/tools/assimp_view/Material.cpp +++ b/tools/assimp_view/Material.cpp @@ -1016,6 +1016,13 @@ int CMaterialManager::CreateMaterial( ++iCurrent; } + if( pcSource->HasBones()) + { + sMacro[iCurrent].Name = "AV_SKINNING"; + sMacro[iCurrent].Definition = "1"; + ++iCurrent; + } + // If a cubemap is active, we'll need to lookup it for calculating // a physically correct reflection if (CBackgroundPainter::TEXTURE_CUBE == CBackgroundPainter::Instance().GetMode()) @@ -1059,11 +1066,11 @@ int CMaterialManager::CreateMaterial( } return 0; } else - { - // use Fixed Function effect when working with shaderless cards - if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0)) - pcMesh->piEffect->SetTechnique( "MaterialFX_FF"); - } + { + // use Fixed Function effect when working with shaderless cards + if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0)) + pcMesh->piEffect->SetTechnique( "MaterialFX_FF"); + } if( piBuffer) piBuffer->Release(); @@ -1225,11 +1232,27 @@ int CMaterialManager::SetupMaterial ( } } + // setup bones if neccessary +// if( pcMesh->HasBones()) + { + static float matrices[4*3*60]; + float* tempmat = matrices; + for( unsigned int a = 0; a < 60; a++) + { + // HACK: (thom) set identity matrices for all bones for the moment so that you see something + *tempmat++ = 1.0f; *tempmat++ = 0.0f; *tempmat++ = 0.0f; *tempmat++ = 0.0f; + *tempmat++ = 0.0f; *tempmat++ = 1.0f; *tempmat++ = 0.0f; *tempmat++ = 0.0f; + *tempmat++ = 0.0f; *tempmat++ = 0.0f; *tempmat++ = 1.0f; *tempmat++ = 0.0f; + } + pcMesh->piEffect->SetVectorArray( "gBoneMatrix", (const D3DXVECTOR4*) matrices, 3*60); + } + + // setup the correct shader technique to be used for drawing - if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0)) - { - g_piDefaultEffect->SetTechnique( "MaterialFXSpecular_FF"); - } else + if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0)) + { + g_piDefaultEffect->SetTechnique( "MaterialFXSpecular_FF"); + } else if (g_sCaps.PixelShaderVersion < D3DPS_VERSION(3,0) || g_sOptions.bLowQuality) { if (g_sOptions.b3Lights) diff --git a/tools/assimp_view/SceneAnimator.cpp b/tools/assimp_view/SceneAnimator.cpp new file mode 100644 index 000000000..5dda79881 --- /dev/null +++ b/tools/assimp_view/SceneAnimator.cpp @@ -0,0 +1,230 @@ +/* +--------------------------------------------------------------------------- +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 "stdafx.h" +#include "assimp_view.h" + +using namespace AssimpView; + +// ------------------------------------------------------------------------------------------------ +// Constructor for a given scene. +SceneAnimator::SceneAnimator( const aiScene* pScene, size_t pAnimIndex) +{ + mScene = pScene; + mCurrentAnimIndex = -1; + mAnimEvaluator = NULL; + mRootNode = NULL; + + // changing the current animation also creates the node tree for this animation + SetAnimIndex( pAnimIndex); +} + +// ------------------------------------------------------------------------------------------------ +// Destructor +SceneAnimator::~SceneAnimator() +{ + delete mRootNode; + delete mAnimEvaluator; +} + +// ------------------------------------------------------------------------------------------------ +// Sets the animation to use for playback. +void SceneAnimator::SetAnimIndex( size_t pAnimIndex) +{ + // no change + if( pAnimIndex == mCurrentAnimIndex) + return; + + // kill data of the previous anim + delete mRootNode; mRootNode = NULL; + delete mAnimEvaluator; mAnimEvaluator = NULL; + mNodesByName.clear(); + + mCurrentAnimIndex = pAnimIndex; + + // create the internal node tree. Do this even in case of invalid animation index + // so that the transformation matrices are properly set up to mimic the current scene + mRootNode = CreateNodeTree( mScene->mRootNode); + + // invalid anim index + if( mCurrentAnimIndex >= mScene->mNumAnimations) + return; + + // create an evaluator for this animation + mAnimEvaluator = new AnimEvaluator( mScene->mAnimations[mCurrentAnimIndex]); +} + +// ------------------------------------------------------------------------------------------------ +// Calculates the node transformations for the scene. +void SceneAnimator::Calculate( double pTime) +{ + // invalid anim + if( !mAnimEvaluator) + return; + + // calculate current local transformations + mAnimEvaluator->Evaluate( pTime); + + // and update all node transformations with the results + UpdateTransforms( mRootNode, mAnimEvaluator->GetTransformations()); +} + +// ------------------------------------------------------------------------------------------------ +// Retrieves the most recent local transformation matrix for the given node. +const aiMatrix4x4& SceneAnimator::GetLocalTransform( const std::string& pNodeName) const +{ + NodeMap::const_iterator it = mNodesByName.find( pNodeName); + if( it == mNodesByName.end()) + return mIdentityMatrix; + + return it->second->mLocalTransform; +} + +// ------------------------------------------------------------------------------------------------ +// Retrieves the most recent global transformation matrix for the given node. +const aiMatrix4x4& SceneAnimator::GetGlobalTransform( const std::string& pNodeName) const +{ + NodeMap::const_iterator it = mNodesByName.find( pNodeName); + if( it == mNodesByName.end()) + return mIdentityMatrix; + + return it->second->mLocalTransform; +} + +// ------------------------------------------------------------------------------------------------ +// Calculates the bone matrices for the given mesh. +const std::vector& SceneAnimator::GetBoneMatrices( const aiNode* pNode, size_t pMeshIndex /* = 0 */) +{ + assert( pMeshIndex < pNode->mNumMeshes); + size_t meshIndex = pNode->mMeshes[pMeshIndex]; + assert( meshIndex < mScene->mNumMeshes); + const aiMesh* mesh = mScene->mMeshes[meshIndex]; + + // resize array and initialise it with identity matrices + mTransforms.resize( mesh->mNumBones, aiMatrix4x4()); + + // calculate the mesh's inverse global transform + aiMatrix4x4 globalInverseMeshTransform = GetGlobalTransform( std::string( pNode->mName.data)); + globalInverseMeshTransform.Inverse(); + + // Bone matrices transform from mesh coordinates in bind pose to mesh coordinates in skinned pose + // Therefore the formula is offsetMatrix * currentGlobalTransform * inverseCurrentMeshTransform + for( size_t a = 0; a < mesh->mNumBones; ++a) + { + const aiBone* bone = mesh->mBones[a]; + const aiMatrix4x4& currentGlobalTransform = GetGlobalTransform( std::string( bone->mName.data)); + mTransforms[a] = bone->mOffsetMatrix * currentGlobalTransform * globalInverseMeshTransform; + } + + // and return the result + return mTransforms; +} + +// ------------------------------------------------------------------------------------------------ +// Recursively creates an internal node structure matching the current scene and animation. +SceneAnimNode* SceneAnimator::CreateNodeTree( aiNode* pNode) +{ + // create a node + SceneAnimNode* internalNode = new SceneAnimNode( pNode->mName.data); + mNodesByName[std::string( pNode->mName.data)] = internalNode; + + // copy its transformation + internalNode->mLocalTransform = pNode->mTransformation; + CalculateGlobalTransform( internalNode); + + // find the index of the animation track affecting this node, if any + if( mCurrentAnimIndex < mScene->mNumAnimations) + { + internalNode->mChannelIndex = -1; + const aiAnimation* currentAnim = mScene->mAnimations[mCurrentAnimIndex]; + for( unsigned int a = 0; a < currentAnim->mNumChannels; a++) + { + if( currentAnim->mChannels[a]->mNodeName.data == internalNode->mName) + { + internalNode->mChannelIndex = a; + break; + } + } + } + + // continue for all child nodes and assign the created internal nodes as our children + for( unsigned int a = 0; a < pNode->mNumChildren; a++) + { + SceneAnimNode* childNode = CreateNodeTree( pNode->mChildren[a]); + childNode->mParent = internalNode; + internalNode->mChildren.push_back( childNode); + } + + return internalNode; +} + +// ------------------------------------------------------------------------------------------------ +// Recursively updates the internal node transformations from the given matrix array +void SceneAnimator::UpdateTransforms( SceneAnimNode* pNode, const std::vector& pTransforms) +{ + // update node local transform + if( pNode->mChannelIndex != -1) + { + assert( pNode->mChannelIndex < pTransforms.size()); + pNode->mLocalTransform = pTransforms[pNode->mChannelIndex]; + + // update global transform as well + CalculateGlobalTransform( pNode); + } + + // continue for all children + for( std::vector::iterator it = pNode->mChildren.begin(); it != pNode->mChildren.end(); ++it) + UpdateTransforms( *it, pTransforms); +} + +// ------------------------------------------------------------------------------------------------ +// Calculates the global transformation matrix for the given internal node +void SceneAnimator::CalculateGlobalTransform( SceneAnimNode* pInternalNode) +{ + // concatenate all parent transforms to get the global transform for this node + pInternalNode->mGlobalTransform = pInternalNode->mLocalTransform; + SceneAnimNode* node = pInternalNode->mParent; + while( node) + { + pInternalNode->mGlobalTransform *= node->mLocalTransform; + node = node->mParent; + } +} diff --git a/tools/assimp_view/SceneAnimator.h b/tools/assimp_view/SceneAnimator.h new file mode 100644 index 000000000..63e1ead83 --- /dev/null +++ b/tools/assimp_view/SceneAnimator.h @@ -0,0 +1,166 @@ +/** Manages animations for a given scene and calculates present transformations for all nodes */ +/* +--------------------------------------------------------------------------- +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. +--------------------------------------------------------------------------- +*/ + +#ifndef AV_SCENEANIMATOR_H_INCLUDED +#define AV_SCENEANIMATOR_H_INCLUDED + +namespace AssimpView +{ + +/** A little tree structure to match the scene's node structure, but holding additional data. Needs to be public + * to allow using it in templates at certain compilers. + */ +struct SceneAnimNode +{ + std::string mName; + SceneAnimNode* mParent; + std::vector mChildren; + aiMatrix4x4 mLocalTransform; // most recently calculated local transform + aiMatrix4x4 mGlobalTransform; // same, but in world space + size_t mChannelIndex; // index in the current animation's channel array. -1 if not animated. + + SceneAnimNode() { mChannelIndex = -1; mParent = NULL; } + SceneAnimNode( const std::string& pName) : mName( pName) { mChannelIndex = -1; mParent = NULL; } + ~SceneAnimNode() { for( std::vector::iterator it = mChildren.begin(); it != mChildren.end(); ++it) delete *it; } +}; + +/** Calculates the animated node transformations for a given scene and timestamp. Create an instance for a aiScene + * you want to animate and set the current animation to play. You can then have the instance calculate the current pose + * for all nodes by calling Calculate() for a given timestamp. After this you can retrieve the present transformation for a given + * node by calling GetLocalTransform() or GetGlobalTransform(). A full set of bone matrices can be retrieved by GetBoneMatrices() + * for a given mesh. + */ +class SceneAnimator +{ +public: + /** Constructor for a given scene. The object keeps a reference to the scene during its lifetime, but ownership + * stays at the caller. + * @param pScene The scene to animate. + * @param pAnimIndex [optional] Index of the animation to play. Assumed to be 0 if not given. + */ + SceneAnimator( const aiScene* pScene, size_t pAnimIndex = 0); + + /** Destructor */ + ~SceneAnimator(); + + /** Sets the animation to use for playback. This also recreates the internal mapping structures, + * which might take a few cycles. + * @param pAnimIndex Index of the animation in the scene's animation array + */ + void SetAnimIndex( size_t pAnimIndex); + + /** Calculates the node transformations for the scene. Call this to get uptodate results + * before calling one of the getters. + * @param pTime Current time. Can be an arbitrary range. + */ + void Calculate( double pTime); + + /** Retrieves the most recent local transformation matrix for the given node. The returned + * matrix is in the node's parent's local space, just like the original node's transformation + * matrix. If the node is not animated, the node's original transformation is returned so that + * you can safely use or assign it to the node itsself. If there is no node with the given name, + * the identity matrix is returned. All transformations are updated whenever Calculate() is called. + * @param pNodeName Name of the node + * @return A reference to the node's most recently calculated local transformation matrix. + */ + const aiMatrix4x4& GetLocalTransform( const std::string& pNodeName) const; + + /** Retrieves the most recent global transformation matrix for the given node. The returned + * matrix is in world space, which is the same coordinate space as the transformation of the + * scene's root node. If the node is not animated, the node's original transformation is + * returned so that you can safely use or assign it to the node itsself. If there is no node + * with the given name, the identity matrix is returned. All transformations are updated whenever + * Calculate() is called. + * @param pNodeName Name of the node + * @return A reference to the node's most recently calculated global transformation matrix. + */ + const aiMatrix4x4& GetGlobalTransform( const std::string& pNodeName) const; + + /** Calculates the bone matrices for the given mesh. Each bone matrix transforms from + * mesh space in bind pose to mesh space in skinned pose, it does not contain the mesh's + * world matrix. Thus the usual matrix chain for using in the vertex shader is + * boneMatrix * worldMatrix * viewMatrix * projMatrix. + * @param pNode The node carrying the mesh. + * @param pMeshIndex Index of the mesh in the node's mesh array. The NODE's mesh array, not + * the scene's mesh array! Leave out to use the first mesh of the node, which is usually + * also the only one. + * @return A reference to a vector of bone matrices. Stays stable till the next call to GetBoneMatrices(); + */ + const std::vector& GetBoneMatrices( const aiNode* pNode, size_t pMeshIndex = 0); + +protected: + /** Recursively creates an internal node structure matching the current scene and animation. */ + SceneAnimNode* CreateNodeTree( aiNode* pNode); + + /** Recursively updates the internal node transformations from the given matrix array */ + void UpdateTransforms( SceneAnimNode* pNode, const std::vector& pTransforms); + + /** Calculates the global transformation matrix for the given internal node */ + void CalculateGlobalTransform( SceneAnimNode* pInternalNode); + +protected: + /** The scene we're operating on */ + const aiScene* mScene; + + /** Current animation index */ + size_t mCurrentAnimIndex; + + /** The AnimEvaluator we use to calculate the current pose for the current animation */ + AnimEvaluator* mAnimEvaluator; + + /** Root node of the internal scene structure */ + SceneAnimNode* mRootNode; + + /** Name to node map to quickly find nodes by their name */ + typedef std::map NodeMap; + NodeMap mNodesByName; + + /** Array to return transformations results inside. */ + std::vector mTransforms; + + /** Identity matrix to return a reference to in case of error */ + aiMatrix4x4 mIdentityMatrix; +}; + +} // end of namespace AssimpView + +#endif // AV_SCENEANIMATOR_H_INCLUDED \ No newline at end of file diff --git a/tools/assimp_view/Shaders.cpp b/tools/assimp_view/Shaders.cpp index d31c9425b..30b0a1174 100644 --- a/tools/assimp_view/Shaders.cpp +++ b/tools/assimp_view/Shaders.cpp @@ -259,11 +259,20 @@ std::string g_szDefaultShader = std::string( // position of the camera in worldspace\n" "float3 vCameraPos : CAMERAPOSITION;\n" + // Bone matrices + "#ifdef AV_SKINNING \n" + "float4x3 gBoneMatrix[60]; \n" + "#endif // AV_SKINNING \n" + // Vertex shader input structure "struct VS_INPUT\n" "{\n" "float3 Position : POSITION;\n" "float3 Normal : NORMAL;\n" + "#ifdef AV_SKINNING \n" + "float4 BlendIndices : BLENDINDICES;\n" + "float4 BlendWeights : BLENDWEIGHT;\n" + "#endif // AV_SKINNING \n" "};\n" // Vertex shader output structure for pixel shader usage @@ -275,8 +284,8 @@ std::string g_szDefaultShader = std::string( "};\n" // Vertex shader output structure for fixed function - "struct VS_OUTPUT_FF\n" - "{\n" + "struct VS_OUTPUT_FF\n" + "{\n" "float4 Position : POSITION;\n" "float4 Color : COLOR;\n" "};\n" @@ -286,9 +295,20 @@ std::string g_szDefaultShader = std::string( "{\n" "VS_OUTPUT Out;\n" + "#ifdef AV_SKINNING \n" + "float4 weights = IN.BlendWeights; \n" + "weights.w = 1.0f - dot( weights.xyz, float3( 1, 1, 1)); \n" + "float3 objPos = mul( IN.Position, gBoneMatrix[IN.BlendIndices.x]) * weights.x; \n" + "objPos += mul( IN.Position, gBoneMatrix[IN.BlendIndices.y]) * weights.y; \n" + "objPos += mul( IN.Position, gBoneMatrix[IN.BlendIndices.z]) * weights.z; \n" + "objPos += mul( IN.Position, gBoneMatrix[IN.BlendIndices.w]) * weights.w; \n" + "#else \n" + "float3 objPos = IN.Position; \n" + "#endif // AV_SKINNING \n" + // Multiply with the WorldViewProjection matrix - "Out.Position = mul(float4(IN.Position,1.0f),WorldViewProjection);\n" - "float3 WorldPos = mul(float4(IN.Position,1.0f),World);\n" + "Out.Position = mul( float4( objPos, 1.0f), WorldViewProjection);\n" + "float3 WorldPos = mul( float4( objPos, 1.0f), World);\n" "Out.ViewDir = vCameraPos - WorldPos;\n" "Out.Normal = mul(IN.Normal,WorldInverseTranspose);\n" @@ -300,15 +320,27 @@ std::string g_szDefaultShader = std::string( "{\n" "VS_OUTPUT_FF Out;\n" - // Multiply with the WorldViewProjection matrix - "Out.Position = mul(float4(IN.Position,1.0f),WorldViewProjection);\n" - "float3 worldNormal = normalize( mul( IN.Normal, (float3x3) WorldInverseTranspose)); \n" + "#ifdef AV_SKINNING \n" + "float4 weights = IN.BlendWeights; \n" + "weights.w = 1.0f - dot( weights.xyz, float3( 1, 1, 1)); \n" + "float3 objPos = mul( IN.Position, gBoneMatrix[IN.BlendIndices.x]) * weights.x; \n" + "objPos += mul( IN.Position, gBoneMatrix[IN.BlendIndices.y]) * weights.y; \n" + "objPos += mul( IN.Position, gBoneMatrix[IN.BlendIndices.z]) * weights.z; \n" + "objPos += mul( IN.Position, gBoneMatrix[IN.BlendIndices.w]) * weights.w; \n" + "#else \n" + "float3 objPos = IN.Position; \n" + "#endif // AV_SKINNING \n" - // per-vertex lighting. We simply assume light colors of unused lights to be black - "Out.Color = float4( 0.2f, 0.2f, 0.2f, 1.0f); \n" - "for( int a = 0; a < 2; a++)\n" - " Out.Color.rgb += saturate( dot( afLightDir[a], worldNormal)) * afLightColor[a].rgb; \n" - "return Out;\n" + // Multiply with the WorldViewProjection matrix + "Out.Position = mul( float4( objPos, 1.0f), WorldViewProjection);\n" + + "float3 worldNormal = normalize( mul( IN.Normal, (float3x3) WorldInverseTranspose)); \n" + + // per-vertex lighting. We simply assume light colors of unused lights to be black + "Out.Color = float4( 0.2f, 0.2f, 0.2f, 1.0f); \n" + "for( int a = 0; a < 2; a++)\n" + " Out.Color.rgb += saturate( dot( afLightDir[a], worldNormal)) * afLightColor[a].rgb; \n" + "return Out;\n" "}\n" // Pixel shader for one light @@ -434,17 +466,17 @@ std::string g_szDefaultShader = std::string( "}\n" "};\n" - // Technique for the default effect using the fixed function pixel pipeline + // Technique for the default effect using the fixed function pixel pipeline "technique DefaultFXSpecular_FF\n" - "{\n" + "{\n" "pass p0\n" - "{\n" + "{\n" "CullMode=none;\n" "VertexShader = compile vs_2_0 DefaultVShader_FF();\n" - "ColorOp[0] = SelectArg1;\n" - "ColorArg0[0] = Diffuse;\n" - "AlphaOp[0] = SelectArg1;\n" - "AlphaArg0[0] = Diffuse;\n" + "ColorOp[0] = SelectArg1;\n" + "ColorArg0[0] = Diffuse;\n" + "AlphaOp[0] = SelectArg1;\n" + "AlphaArg0[0] = Diffuse;\n" "}\n" "};\n" ); @@ -486,6 +518,11 @@ std::string g_szMaterialShader = std::string( // position of the camera in worldspace "float3 vCameraPos : CAMERAPOSITION;\n" + // Bone matrices + "#ifdef AV_SKINNING \n" + "float4x3 gBoneMatrix[60]; \n" + "#endif // AV_SKINNING \n" + "#ifdef AV_DIFFUSE_TEXTURE\n" "texture DIFFUSE_TEXTURE;\n" "sampler DIFFUSE_SAMPLER\n" @@ -574,6 +611,10 @@ std::string g_szMaterialShader = std::string( "float3 Tangent : TEXCOORD0;\n" "float3 Bitangent : TEXCOORD1;\n" "float2 TexCoord0 : TEXCOORD2;\n" + "#ifdef AV_SKINNING \n" + "float4 BlendIndices : BLENDINDICES;\n" + "float4 BlendWeights : BLENDWEIGHT;\n" + "#endif // AV_SKINNING \n" "};\n" // Vertex shader output structure for pixel shader usage @@ -598,8 +639,8 @@ std::string g_szMaterialShader = std::string( "struct VS_OUTPUT_FF\n" "{\n" "float4 Position : POSITION;\n" - "float4 DiffuseColor : COLOR0;\n" - "float4 SpecularColor : COLOR1;\n" + "float4 DiffuseColor : COLOR0;\n" + "float4 SpecularColor : COLOR1;\n" "float2 TexCoord0 : TEXCOORD0;\n" "};\n" @@ -650,9 +691,20 @@ std::string g_szMaterialShader = std::string( "{\n" "VS_OUTPUT Out;\n" - // Multiply with the WorldViewProjection matrix\n" - "Out.Position = mul(float4(IN.Position,1.0f),WorldViewProjection);\n" - "float3 WorldPos = mul(float4(IN.Position,1.0f),World);\n" + "#ifdef AV_SKINNING \n" + "float4 weights = IN.BlendWeights; \n" + "weights.w = 1.0f - dot( weights.xyz, float3( 1, 1, 1)); \n" + "float3 objPos = mul( IN.Position, gBoneMatrix[IN.BlendIndices.x]) * weights.x; \n" + "objPos += mul( IN.Position, gBoneMatrix[IN.BlendIndices.y]) * weights.y; \n" + "objPos += mul( IN.Position, gBoneMatrix[IN.BlendIndices.z]) * weights.z; \n" + "objPos += mul( IN.Position, gBoneMatrix[IN.BlendIndices.w]) * weights.w; \n" + "#else \n" + "float3 objPos = IN.Position; \n" + "#endif // AV_SKINNING \n" + + // Multiply with the WorldViewProjection matrix + "Out.Position = mul( float4( objPos, 1.0f), WorldViewProjection);\n" + "float3 WorldPos = mul( float4( objPos, 1.0f), World);\n" "Out.TexCoord0 = IN.TexCoord0;\n" "#ifndef AV_NORMAL_TEXTURE\n" @@ -674,9 +726,20 @@ std::string g_szMaterialShader = std::string( "{\n" "VS_OUTPUT Out;\n" - // Multiply with the WorldViewProjection matrix\n" - "Out.Position = mul(float4(IN.Position,1.0f),WorldViewProjection);\n" - "float3 WorldPos = mul(float4(IN.Position,1.0f),World);\n" + "#ifdef AV_SKINNING \n" + "float4 weights = IN.BlendWeights; \n" + "weights.w = 1.0f - dot( weights.xyz, float3( 1, 1, 1)); \n" + "float3 objPos = mul( IN.Position, gBoneMatrix[IN.BlendIndices.x]) * weights.x; \n" + "objPos += mul( IN.Position, gBoneMatrix[IN.BlendIndices.y]) * weights.y; \n" + "objPos += mul( IN.Position, gBoneMatrix[IN.BlendIndices.z]) * weights.z; \n" + "objPos += mul( IN.Position, gBoneMatrix[IN.BlendIndices.w]) * weights.w; \n" + "#else \n" + "float3 objPos = IN.Position; \n" + "#endif // AV_SKINNING \n" + + // Multiply with the WorldViewProjection matrix + "Out.Position = mul( float4( objPos, 1.0f), WorldViewProjection);\n" + "float3 WorldPos = mul( float4( objPos, 1.0f), World);\n" "Out.TexCoord0 = IN.TexCoord0;\n" "#ifndef AV_NORMAL_TEXTURE\n" @@ -699,32 +762,43 @@ std::string g_szMaterialShader = std::string( "{\n" "VS_OUTPUT_FF Out;\n" + "#ifdef AV_SKINNING \n" + "float4 weights = IN.BlendWeights; \n" + "weights.w = 1.0f - dot( weights.xyz, float3( 1, 1, 1)); \n" + "float3 objPos = mul( IN.Position, gBoneMatrix[IN.BlendIndices.x]) * weights.x; \n" + "objPos += mul( IN.Position, gBoneMatrix[IN.BlendIndices.y]) * weights.y; \n" + "objPos += mul( IN.Position, gBoneMatrix[IN.BlendIndices.z]) * weights.z; \n" + "objPos += mul( IN.Position, gBoneMatrix[IN.BlendIndices.w]) * weights.w; \n" + "#else \n" + "float3 objPos = IN.Position; \n" + "#endif // AV_SKINNING \n" + // Multiply with the WorldViewProjection matrix - "Out.Position = mul( float4( IN.Position, 1.0f), WorldViewProjection);\n" - "float3 worldPos = mul( float4( IN.Position, 1.0f), World);\n" - "float3 worldNormal = normalize( mul( IN.Normal, (float3x3) WorldInverseTranspose)); \n" + "Out.Position = mul( float4( objPos, 1.0f), WorldViewProjection);\n" + "float3 worldPos = mul( float4( objPos, 1.0f), World);\n" + "float3 worldNormal = normalize( mul( IN.Normal, (float3x3) WorldInverseTranspose)); \n" "Out.TexCoord0 = IN.TexCoord0;\n" - // calculate per-vertex diffuse lighting including ambient part - "float4 diffuseColor = float4( 0.0f, 0.0f, 0.0f, 1.0f); \n" - "for( int a = 0; a < 2; a++) \n" - " diffuseColor.rgb += saturate( dot( afLightDir[a], worldNormal)) * afLightColor[a].rgb; \n" - // factor in material properties and a bit of ambient lighting - "Out.DiffuseColor = diffuseColor * DIFFUSE_COLOR + float4( 0.2f, 0.2f, 0.2f, 1.0f) * AMBIENT_COLOR; ; \n" + // calculate per-vertex diffuse lighting including ambient part + "float4 diffuseColor = float4( 0.0f, 0.0f, 0.0f, 1.0f); \n" + "for( int a = 0; a < 2; a++) \n" + " diffuseColor.rgb += saturate( dot( afLightDir[a], worldNormal)) * afLightColor[a].rgb; \n" + // factor in material properties and a bit of ambient lighting + "Out.DiffuseColor = diffuseColor * DIFFUSE_COLOR + float4( 0.2f, 0.2f, 0.2f, 1.0f) * AMBIENT_COLOR; ; \n" - // and specular including emissive part - "float4 specularColor = float4( 0.0f, 0.0f, 0.0f, 1.0f); \n" - "#ifdef AV_SPECULAR_COMPONENT\n" - "float3 viewDir = normalize( worldPos - vCameraPos); \n" - "for( int a = 0; a < 2; a++) \n" - "{ \n" - " float3 reflDir = reflect( afLightDir[a], worldNormal); \n" - " float specIntensity = pow( saturate( dot( reflDir, viewDir)), SPECULARITY) * SPECULAR_STRENGTH; \n" - " specularColor.rgb += afLightColor[a] * specIntensity; \n" - "} \n" - "#endif // AV_SPECULAR_COMPONENT\n" - // factor in material properties and the emissive part - "Out.SpecularColor = specularColor * SPECULAR_COLOR + EMISSIVE_COLOR; \n" + // and specular including emissive part + "float4 specularColor = float4( 0.0f, 0.0f, 0.0f, 1.0f); \n" + "#ifdef AV_SPECULAR_COMPONENT\n" + "float3 viewDir = normalize( worldPos - vCameraPos); \n" + "for( int a = 0; a < 2; a++) \n" + "{ \n" + " float3 reflDir = reflect( afLightDir[a], worldNormal); \n" + " float specIntensity = pow( saturate( dot( reflDir, viewDir)), SPECULARITY) * SPECULAR_STRENGTH; \n" + " specularColor.rgb += afLightColor[a] * specIntensity; \n" + "} \n" + "#endif // AV_SPECULAR_COMPONENT\n" + // factor in material properties and the emissive part + "Out.SpecularColor = specularColor * SPECULAR_COLOR + EMISSIVE_COLOR; \n" "return Out;\n" "}\n" @@ -1157,14 +1231,14 @@ std::string g_szMaterialShader = std::string( "pass p0\n" "{\n" "CullMode=none;\n" - "SpecularEnable = true; \n" + "SpecularEnable = true; \n" "VertexShader = compile vs_2_0 MaterialVShader_FF();\n" - "ColorOp[0] = Modulate;\n" - "ColorArg0[0] = Texture;\n" - "ColorArg1[0] = Diffuse;\n" - "AlphaOp[0] = Modulate;\n" - "AlphaArg0[0] = Texture;\n" - "AlphaArg1[0] = Diffuse;\n" + "ColorOp[0] = Modulate;\n" + "ColorArg0[0] = Texture;\n" + "ColorArg1[0] = Diffuse;\n" + "AlphaOp[0] = Modulate;\n" + "AlphaArg0[0] = Texture;\n" + "AlphaArg1[0] = Diffuse;\n" "}\n" "};\n" ); diff --git a/tools/assimp_view/assimp_view.cpp b/tools/assimp_view/assimp_view.cpp index ea3e48db0..788f2bec7 100644 --- a/tools/assimp_view/assimp_view.cpp +++ b/tools/assimp_view/assimp_view.cpp @@ -55,6 +55,7 @@ HINSTANCE g_hInstance = NULL; HWND g_hDlg = NULL; IDirect3D9* g_piD3D = NULL; IDirect3DDevice9* g_piDevice = NULL; +IDirect3DVertexDeclaration9* gDefaultVertexDecl = NULL; double g_fFPS = 0.0f; char g_szFileName[MAX_PATH]; ID3DXEffect* g_piDefaultEffect = NULL; @@ -222,6 +223,9 @@ int LoadAsset(void) g_pcAsset->apcMeshes[i] = new AssetHelper::MeshHelper(); } + // create animator + g_pcAsset->mAnimator = new SceneAnimator( g_pcAsset->pcScene); + // build a new caption string for the viewer char szOut[MAX_PATH + 10]; sprintf(szOut,AI_VIEW_CAPTION_BASE " [%s]",g_szFileName); @@ -272,6 +276,7 @@ int DeleteAsset(void) } aiReleaseImport(g_pcAsset->pcScene); delete[] g_pcAsset->apcMeshes; + delete g_pcAsset->mAnimator; delete g_pcAsset; g_pcAsset = NULL; @@ -430,23 +435,25 @@ int CreateAssetData() for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) { + const aiMesh* mesh = g_pcAsset->pcScene->mMeshes[i]; + // create the material for the mesh if (!g_pcAsset->apcMeshes[i]->piEffect) { CMaterialManager::Instance().CreateMaterial( - g_pcAsset->apcMeshes[i],g_pcAsset->pcScene->mMeshes[i]); + g_pcAsset->apcMeshes[i],mesh); } - if (g_pcAsset->pcScene->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType_TRIANGLE) + if (mesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE) { continue; } // create vertex buffer if(FAILED( g_piDevice->CreateVertexBuffer(sizeof(AssetHelper::Vertex) * - g_pcAsset->pcScene->mMeshes[i]->mNumVertices, + mesh->mNumVertices, D3DUSAGE_WRITEONLY, - AssetHelper::Vertex::GetFVF(), + 0, D3DPOOL_DEFAULT, &g_pcAsset->apcMeshes[i]->piVB,NULL))) { MessageBox(g_hDlg,"Failed to create vertex buffer", @@ -459,11 +466,11 @@ int CreateAssetData() dwUsage |= D3DUSAGE_DYNAMIC; // check whether we can use 16 bit indices - if (g_pcAsset->pcScene->mMeshes[i]->mNumFaces * 3 >= 65536) + if (mesh->mNumFaces * 3 >= 65536) { // create 32 bit index buffer if(FAILED( g_piDevice->CreateIndexBuffer( 4 * - g_pcAsset->pcScene->mMeshes[i]->mNumFaces * 3, + mesh->mNumFaces * 3, D3DUSAGE_WRITEONLY | dwUsage, D3DFMT_INDEX32, D3DPOOL_DEFAULT, @@ -478,11 +485,11 @@ int CreateAssetData() // now fill the index buffer unsigned int* pbData; g_pcAsset->apcMeshes[i]->piIB->Lock(0,0,(void**)&pbData,0); - for (unsigned int x = 0; x < g_pcAsset->pcScene->mMeshes[i]->mNumFaces;++x) + for (unsigned int x = 0; x < mesh->mNumFaces;++x) { for (unsigned int a = 0; a < 3;++a) { - *pbData++ = g_pcAsset->pcScene->mMeshes[i]->mFaces[x].mIndices[a]; + *pbData++ = mesh->mFaces[x].mIndices[a]; } } } @@ -490,7 +497,7 @@ int CreateAssetData() { // create 16 bit index buffer if(FAILED( g_piDevice->CreateIndexBuffer( 2 * - g_pcAsset->pcScene->mMeshes[i]->mNumFaces * 3, + mesh->mNumFaces * 3, D3DUSAGE_WRITEONLY | dwUsage, D3DFMT_INDEX16, D3DPOOL_DEFAULT, @@ -505,56 +512,86 @@ int CreateAssetData() // now fill the index buffer uint16_t* pbData; g_pcAsset->apcMeshes[i]->piIB->Lock(0,0,(void**)&pbData,0); - for (unsigned int x = 0; x < g_pcAsset->pcScene->mMeshes[i]->mNumFaces;++x) + for (unsigned int x = 0; x < mesh->mNumFaces;++x) { for (unsigned int a = 0; a < 3;++a) { - *pbData++ = (uint16_t)g_pcAsset->pcScene->mMeshes[i]->mFaces[x].mIndices[a]; + *pbData++ = (uint16_t)mesh->mFaces[x].mIndices[a]; } } } g_pcAsset->apcMeshes[i]->piIB->Unlock(); + // collect weights on all vertices. Quick and careless + std::vector > weightsPerVertex( mesh->mNumVertices); + for( unsigned int a = 0; a < mesh->mNumBones; a++) + { + const aiBone* bone = mesh->mBones[a]; + for( unsigned int b = 0; b < bone->mNumWeights; b++) + weightsPerVertex[bone->mWeights[b].mVertexId].push_back( aiVertexWeight( a, bone->mWeights[b].mWeight)); + } + // now fill the vertex buffer AssetHelper::Vertex* pbData2; g_pcAsset->apcMeshes[i]->piVB->Lock(0,0,(void**)&pbData2,0); - for (unsigned int x = 0; x < g_pcAsset->pcScene->mMeshes[i]->mNumVertices;++x) + for (unsigned int x = 0; x < mesh->mNumVertices;++x) { - pbData2->vPosition = g_pcAsset->pcScene->mMeshes[i]->mVertices[x]; + pbData2->vPosition = mesh->mVertices[x]; - if (NULL == g_pcAsset->pcScene->mMeshes[i]->mNormals) + if (NULL == mesh->mNormals) pbData2->vNormal = aiVector3D(0.0f,0.0f,0.0f); - else pbData2->vNormal = g_pcAsset->pcScene->mMeshes[i]->mNormals[x]; + else pbData2->vNormal = mesh->mNormals[x]; - if (NULL == g_pcAsset->pcScene->mMeshes[i]->mTangents) + if (NULL == mesh->mTangents) { pbData2->vTangent = aiVector3D(0.0f,0.0f,0.0f); pbData2->vBitangent = aiVector3D(0.0f,0.0f,0.0f); } else { - pbData2->vTangent = g_pcAsset->pcScene->mMeshes[i]->mTangents[x]; - pbData2->vBitangent = g_pcAsset->pcScene->mMeshes[i]->mBitangents[x]; + pbData2->vTangent = mesh->mTangents[x]; + pbData2->vBitangent = mesh->mBitangents[x]; } - if (g_pcAsset->pcScene->mMeshes[i]->HasVertexColors( 0)) + if (mesh->HasVertexColors( 0)) { pbData2->dColorDiffuse = D3DCOLOR_ARGB( - ((unsigned char)std::max( std::min( g_pcAsset->pcScene->mMeshes[i]->mColors[0][x].a * 255.0f, 255.0f),0.0f)), - ((unsigned char)std::max( std::min( g_pcAsset->pcScene->mMeshes[i]->mColors[0][x].r * 255.0f, 255.0f),0.0f)), - ((unsigned char)std::max( std::min( g_pcAsset->pcScene->mMeshes[i]->mColors[0][x].g * 255.0f, 255.0f),0.0f)), - ((unsigned char)std::max( std::min( g_pcAsset->pcScene->mMeshes[i]->mColors[0][x].b * 255.0f, 255.0f),0.0f))); + ((unsigned char)std::max( std::min( mesh->mColors[0][x].a * 255.0f, 255.0f),0.0f)), + ((unsigned char)std::max( std::min( mesh->mColors[0][x].r * 255.0f, 255.0f),0.0f)), + ((unsigned char)std::max( std::min( mesh->mColors[0][x].g * 255.0f, 255.0f),0.0f)), + ((unsigned char)std::max( std::min( mesh->mColors[0][x].b * 255.0f, 255.0f),0.0f))); } else pbData2->dColorDiffuse = D3DCOLOR_ARGB(0xFF,0,0,0); // ignore a third texture coordinate component - if (g_pcAsset->pcScene->mMeshes[i]->HasTextureCoords( 0)) + if (mesh->HasTextureCoords( 0)) { pbData2->vTextureUV = aiVector2D( - g_pcAsset->pcScene->mMeshes[i]->mTextureCoords[0][x].x, - g_pcAsset->pcScene->mMeshes[i]->mTextureCoords[0][x].y); + mesh->mTextureCoords[0][x].x, + mesh->mTextureCoords[0][x].y); } else pbData2->vTextureUV = aiVector2D(0.0f,0.0f); + + // Bone indices and weights + if( mesh->HasBones()) + { + unsigned char boneIndices[4] = { 0, 0, 0, 0 }; + unsigned char boneWeights[4] = { 0, 0, 0, 0 }; + assert( weightsPerVertex[x].size() <= 4); + for( unsigned int a = 0; a < weightsPerVertex[x].size(); a++) + { + boneIndices[a] = weightsPerVertex[x][a].mVertexId; + boneWeights[a] = (unsigned char) (weightsPerVertex[x][a].mWeight * 255.0f); + } + + memcpy( pbData2->mBoneIndices, boneIndices, sizeof( boneIndices)); + memcpy( pbData2->mBoneWeights, boneWeights, sizeof( boneWeights)); + } else + { + memset( pbData2->mBoneIndices, 0, sizeof( pbData2->mBoneIndices)); + memset( pbData2->mBoneWeights, 0, sizeof( pbData2->mBoneWeights)); + } + ++pbData2; } g_pcAsset->apcMeshes[i]->piVB->Unlock(); @@ -562,7 +599,7 @@ int CreateAssetData() // now generate the second vertex buffer, holding all normals if (!g_pcAsset->apcMeshes[i]->piVBNormals) { - GenerateNormalsAsLineList(g_pcAsset->apcMeshes[i],g_pcAsset->pcScene->mMeshes[i]); + GenerateNormalsAsLineList(g_pcAsset->apcMeshes[i],mesh); } } return 1; @@ -743,6 +780,12 @@ int ShutdownDevice(void) g_pcTexture = NULL; } + if( NULL != gDefaultVertexDecl) + { + gDefaultVertexDecl->Release(); + gDefaultVertexDecl = NULL; + } + // delete the main D3D device object if (NULL != g_piDevice) { @@ -914,13 +957,13 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/) sParams.MultiSampleType = sMSOut; } - // preget the device capabilities. If the hardware vertex shader is too old, we prefer software vertex processing - g_piD3D->GetDeviceCaps( 0, D3DDEVTYPE_HAL, &g_sCaps); - DWORD creationFlags = D3DCREATE_MULTITHREADED; - if( g_sCaps.VertexShaderVersion >= D3DVS_VERSION( 2, 0)) - creationFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING; - else - creationFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; + // preget the device capabilities. If the hardware vertex shader is too old, we prefer software vertex processing + g_piD3D->GetDeviceCaps( 0, D3DDEVTYPE_HAL, &g_sCaps); + DWORD creationFlags = D3DCREATE_MULTITHREADED; + if( g_sCaps.VertexShaderVersion >= D3DVS_VERSION( 2, 0)) + creationFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING; + else + creationFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; // create the D3D9 device object. with software-vertexprocessing if VS2.0 isn`t supported in hardware if(FAILED(g_piD3D->CreateDevice(0,eType, g_hDlg, creationFlags ,&sParams,&g_piDevice))) @@ -929,7 +972,15 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/) if (bHW)return CreateDevice(p_bMultiSample,p_bSuperSample,false); return 0; } - g_piDevice->SetFVF(AssetHelper::Vertex::GetFVF()); + + // create a vertex declaration to match the vertex + D3DVERTEXELEMENT9* vdecl = AssetHelper::Vertex::GetDeclarationElements(); + if( FAILED( g_piDevice->CreateVertexDeclaration( vdecl, &gDefaultVertexDecl))) + { + MessageBox( g_hDlg, "Failed to create vertex declaration", "Init", MB_OK); + return 0; + } + g_piDevice->SetVertexDeclaration( gDefaultVertexDecl); // get the capabilities of the device object g_piDevice->GetDeviceCaps(&g_sCaps); @@ -962,9 +1013,9 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/) piBuffer = NULL; } - // use Fixed Function effect when working with shaderless cards - if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0)) - g_piDefaultEffect->SetTechnique( "DefaultFXSpecular_FF"); + // use Fixed Function effect when working with shaderless cards + if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0)) + g_piDefaultEffect->SetTechnique( "DefaultFXSpecular_FF"); // create the shader used to draw the HUD if(FAILED( D3DXCreateEffect(g_piDevice, @@ -984,9 +1035,9 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/) piBuffer = NULL; } - // use Fixed Function effect when working with shaderless cards - if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0)) - g_piPassThroughEffect->SetTechnique( "PassThrough_FF"); + // use Fixed Function effect when working with shaderless cards + if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0)) + g_piPassThroughEffect->SetTechnique( "PassThrough_FF"); // create the shader used to visualize normal vectors if(FAILED( D3DXCreateEffect(g_piDevice, @@ -1006,9 +1057,9 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/) piBuffer = NULL; } - // use Fixed Function effect when working with shaderless cards - if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0)) - g_piNormalsEffect->SetTechnique( "RenderNormals_FF"); + // use Fixed Function effect when working with shaderless cards + if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0)) + g_piNormalsEffect->SetTechnique( "RenderNormals_FF"); // create the texture for the HUD CreateHUDTexture(); diff --git a/tools/assimp_view/assimp_view.h b/tools/assimp_view/assimp_view.h index 42a16e669..c9c1014b5 100644 --- a/tools/assimp_view/assimp_view.h +++ b/tools/assimp_view/assimp_view.h @@ -73,7 +73,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; -namespace AssimpView { +namespace AssimpView +{ #include "AssetHelper.h" #include "Camera.h" @@ -86,6 +87,15 @@ namespace AssimpView { #include "MeshRenderer.h" #include "MaterialManager.h" +} // end of namespace AssimpView - for a while + +// outside of namespace, to help Intellisense and solve boost::metatype_stuff_miracle +#include "AnimEvaluator.h" +#include "SceneAnimator.h" + +namespace AssimpView +{ + //------------------------------------------------------------------------------- // Function prototypes //------------------------------------------------------------------------------- @@ -196,6 +206,7 @@ enum EClickPos extern HWND g_hDlg /*= NULL*/; extern IDirect3D9* g_piD3D /*= NULL*/; extern IDirect3DDevice9* g_piDevice /*= NULL*/; + extern IDirect3DVertexDeclaration9* gDefaultVertexDecl /*= NULL*/; extern double g_fFPS /*= 0.0f*/; extern char g_szFileName[MAX_PATH]; extern ID3DXEffect* g_piDefaultEffect /*= NULL*/; @@ -241,7 +252,7 @@ enum EClickPos extern RenderOptions g_sOptions; extern Camera g_sCamera; extern AssetHelper *g_pcAsset /*= NULL*/; - + // // Contains the mask image for the HUD @@ -257,7 +268,4 @@ enum EClickPos extern IDirect3DQuery9* g_piQuery; } -// outside of namespace, to help Intellisense and solve boost::metatype_stuff_miracle -#include "AnimEvaluator.h" - #endif // !! AV_MAIN_H_INCLUDED \ No newline at end of file diff --git a/tools/assimp_view/stdafx.h b/tools/assimp_view/stdafx.h index 3e8b68247..31fb36d3c 100644 --- a/tools/assimp_view/stdafx.h +++ b/tools/assimp_view/stdafx.h @@ -28,6 +28,7 @@ #include // C RunTime-Headerdateien +#include #include #include #include diff --git a/workspaces/vc8/assimp_view.vcproj b/workspaces/vc8/assimp_view.vcproj index 385c32cff..cf769044f 100644 --- a/workspaces/vc8/assimp_view.vcproj +++ b/workspaces/vc8/assimp_view.vcproj @@ -775,6 +775,14 @@ RelativePath="..\..\tools\assimp_view\Resource.h" > + + + +