vrshoot
diff libs/assimp/SkeletonMeshBuilder.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/SkeletonMeshBuilder.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,267 @@ 1.4 +/* 1.5 +Open Asset Import Library (assimp) 1.6 +---------------------------------------------------------------------- 1.7 + 1.8 +Copyright (c) 2006-2012, assimp team 1.9 +All rights reserved. 1.10 + 1.11 +Redistribution and use of this software in source and binary forms, 1.12 +with or without modification, are permitted provided that the 1.13 +following conditions are met: 1.14 + 1.15 +* Redistributions of source code must retain the above 1.16 +copyright notice, this list of conditions and the 1.17 +following disclaimer. 1.18 + 1.19 +* Redistributions in binary form must reproduce the above 1.20 +copyright notice, this list of conditions and the 1.21 +following disclaimer in the documentation and/or other 1.22 +materials provided with the distribution. 1.23 + 1.24 +* Neither the name of the assimp team, nor the names of its 1.25 +contributors may be used to endorse or promote products 1.26 +derived from this software without specific prior 1.27 +written permission of the assimp team. 1.28 + 1.29 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.30 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.31 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.32 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.33 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.34 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.35 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.36 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.37 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.38 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.39 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.40 + 1.41 +---------------------------------------------------------------------- 1.42 +*/ 1.43 + 1.44 +/** @file SkeletonMeshBuilder.cpp 1.45 + * @brief Implementation of a little class to construct a dummy mesh for a skeleton 1.46 + */ 1.47 + 1.48 +#include "AssimpPCH.h" 1.49 +#include "assimp/scene.h" 1.50 +#include "SkeletonMeshBuilder.h" 1.51 + 1.52 +using namespace Assimp; 1.53 + 1.54 +// ------------------------------------------------------------------------------------------------ 1.55 +// The constructor processes the given scene and adds a mesh there. 1.56 +SkeletonMeshBuilder::SkeletonMeshBuilder( aiScene* pScene, aiNode* root, bool bKnobsOnly) 1.57 +{ 1.58 + // nothing to do if there's mesh data already present at the scene 1.59 + if( pScene->mNumMeshes > 0 || pScene->mRootNode == NULL) 1.60 + return; 1.61 + 1.62 + if (!root) 1.63 + root = pScene->mRootNode; 1.64 + 1.65 + mKnobsOnly = bKnobsOnly; 1.66 + 1.67 + // build some faces around each node 1.68 + CreateGeometry( root ); 1.69 + 1.70 + // create a mesh to hold all the generated faces 1.71 + pScene->mNumMeshes = 1; 1.72 + pScene->mMeshes = new aiMesh*[1]; 1.73 + pScene->mMeshes[0] = CreateMesh(); 1.74 + // and install it at the root node 1.75 + root->mNumMeshes = 1; 1.76 + root->mMeshes = new unsigned int[1]; 1.77 + root->mMeshes[0] = 0; 1.78 + 1.79 + // create a dummy material for the mesh 1.80 + pScene->mNumMaterials = 1; 1.81 + pScene->mMaterials = new aiMaterial*[1]; 1.82 + pScene->mMaterials[0] = CreateMaterial(); 1.83 +} 1.84 + 1.85 +// ------------------------------------------------------------------------------------------------ 1.86 +// Recursively builds a simple mesh representation for the given node 1.87 +void SkeletonMeshBuilder::CreateGeometry( const aiNode* pNode) 1.88 +{ 1.89 + // add a joint entry for the node. 1.90 + const unsigned int vertexStartIndex = mVertices.size(); 1.91 + 1.92 + // now build the geometry. 1.93 + if( pNode->mNumChildren > 0 && !mKnobsOnly) 1.94 + { 1.95 + // If the node has children, we build little pointers to each of them 1.96 + for( unsigned int a = 0; a < pNode->mNumChildren; a++) 1.97 + { 1.98 + // find a suitable coordinate system 1.99 + const aiMatrix4x4& childTransform = pNode->mChildren[a]->mTransformation; 1.100 + aiVector3D childpos( childTransform.a4, childTransform.b4, childTransform.c4); 1.101 + float distanceToChild = childpos.Length(); 1.102 + if( distanceToChild < 0.0001f) 1.103 + continue; 1.104 + aiVector3D up = aiVector3D( childpos).Normalize(); 1.105 + 1.106 + aiVector3D orth( 1.0f, 0.0f, 0.0f); 1.107 + if( fabs( orth * up) > 0.99f) 1.108 + orth.Set( 0.0f, 1.0f, 0.0f); 1.109 + 1.110 + aiVector3D front = (up ^ orth).Normalize(); 1.111 + aiVector3D side = (front ^ up).Normalize(); 1.112 + 1.113 + unsigned int localVertexStart = mVertices.size(); 1.114 + mVertices.push_back( -front * distanceToChild * 0.1f); 1.115 + mVertices.push_back( childpos); 1.116 + mVertices.push_back( -side * distanceToChild * 0.1f); 1.117 + mVertices.push_back( -side * distanceToChild * 0.1f); 1.118 + mVertices.push_back( childpos); 1.119 + mVertices.push_back( front * distanceToChild * 0.1f); 1.120 + mVertices.push_back( front * distanceToChild * 0.1f); 1.121 + mVertices.push_back( childpos); 1.122 + mVertices.push_back( side * distanceToChild * 0.1f); 1.123 + mVertices.push_back( side * distanceToChild * 0.1f); 1.124 + mVertices.push_back( childpos); 1.125 + mVertices.push_back( -front * distanceToChild * 0.1f); 1.126 + 1.127 + mFaces.push_back( Face( localVertexStart + 0, localVertexStart + 1, localVertexStart + 2)); 1.128 + mFaces.push_back( Face( localVertexStart + 3, localVertexStart + 4, localVertexStart + 5)); 1.129 + mFaces.push_back( Face( localVertexStart + 6, localVertexStart + 7, localVertexStart + 8)); 1.130 + mFaces.push_back( Face( localVertexStart + 9, localVertexStart + 10, localVertexStart + 11)); 1.131 + } 1.132 + } 1.133 + else 1.134 + { 1.135 + // if the node has no children, it's an end node. Put a little knob there instead 1.136 + aiVector3D ownpos( pNode->mTransformation.a4, pNode->mTransformation.b4, pNode->mTransformation.c4); 1.137 + float sizeEstimate = ownpos.Length() * 0.18f; 1.138 + 1.139 + mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f)); 1.140 + mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f)); 1.141 + mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate)); 1.142 + mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f)); 1.143 + mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f)); 1.144 + mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate)); 1.145 + mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f)); 1.146 + mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f)); 1.147 + mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate)); 1.148 + mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f)); 1.149 + mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f)); 1.150 + mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate)); 1.151 + 1.152 + mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f)); 1.153 + mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate)); 1.154 + mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f)); 1.155 + mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f)); 1.156 + mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate)); 1.157 + mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f)); 1.158 + mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f)); 1.159 + mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate)); 1.160 + mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f)); 1.161 + mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f)); 1.162 + mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate)); 1.163 + mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f)); 1.164 + 1.165 + mFaces.push_back( Face( vertexStartIndex + 0, vertexStartIndex + 1, vertexStartIndex + 2)); 1.166 + mFaces.push_back( Face( vertexStartIndex + 3, vertexStartIndex + 4, vertexStartIndex + 5)); 1.167 + mFaces.push_back( Face( vertexStartIndex + 6, vertexStartIndex + 7, vertexStartIndex + 8)); 1.168 + mFaces.push_back( Face( vertexStartIndex + 9, vertexStartIndex + 10, vertexStartIndex + 11)); 1.169 + mFaces.push_back( Face( vertexStartIndex + 12, vertexStartIndex + 13, vertexStartIndex + 14)); 1.170 + mFaces.push_back( Face( vertexStartIndex + 15, vertexStartIndex + 16, vertexStartIndex + 17)); 1.171 + mFaces.push_back( Face( vertexStartIndex + 18, vertexStartIndex + 19, vertexStartIndex + 20)); 1.172 + mFaces.push_back( Face( vertexStartIndex + 21, vertexStartIndex + 22, vertexStartIndex + 23)); 1.173 + } 1.174 + 1.175 + unsigned int numVertices = mVertices.size() - vertexStartIndex; 1.176 + if( numVertices > 0) 1.177 + { 1.178 + // create a bone affecting all the newly created vertices 1.179 + aiBone* bone = new aiBone; 1.180 + mBones.push_back( bone); 1.181 + bone->mName = pNode->mName; 1.182 + 1.183 + // calculate the bone offset matrix by concatenating the inverse transformations of all parents 1.184 + bone->mOffsetMatrix = aiMatrix4x4( pNode->mTransformation).Inverse(); 1.185 + for( aiNode* parent = pNode->mParent; parent != NULL; parent = parent->mParent) 1.186 + bone->mOffsetMatrix = aiMatrix4x4( parent->mTransformation).Inverse() * bone->mOffsetMatrix; 1.187 + 1.188 + // add all the vertices to the bone's influences 1.189 + bone->mNumWeights = numVertices; 1.190 + bone->mWeights = new aiVertexWeight[numVertices]; 1.191 + for( unsigned int a = 0; a < numVertices; a++) 1.192 + bone->mWeights[a] = aiVertexWeight( vertexStartIndex + a, 1.0f); 1.193 + 1.194 + // HACK: (thom) transform all vertices to the bone's local space. Should be done before adding 1.195 + // them to the array, but I'm tired now and I'm annoyed. 1.196 + aiMatrix4x4 boneToMeshTransform = aiMatrix4x4( bone->mOffsetMatrix).Inverse(); 1.197 + for( unsigned int a = vertexStartIndex; a < mVertices.size(); a++) 1.198 + mVertices[a] = boneToMeshTransform * mVertices[a]; 1.199 + } 1.200 + 1.201 + // and finally recurse into the children list 1.202 + for( unsigned int a = 0; a < pNode->mNumChildren; a++) 1.203 + CreateGeometry( pNode->mChildren[a]); 1.204 +} 1.205 + 1.206 +// ------------------------------------------------------------------------------------------------ 1.207 +// Creates the mesh from the internally accumulated stuff and returns it. 1.208 +aiMesh* SkeletonMeshBuilder::CreateMesh() 1.209 +{ 1.210 + aiMesh* mesh = new aiMesh(); 1.211 + 1.212 + // add points 1.213 + mesh->mNumVertices = mVertices.size(); 1.214 + mesh->mVertices = new aiVector3D[mesh->mNumVertices]; 1.215 + std::copy( mVertices.begin(), mVertices.end(), mesh->mVertices); 1.216 + 1.217 + mesh->mNormals = new aiVector3D[mesh->mNumVertices]; 1.218 + 1.219 + // add faces 1.220 + mesh->mNumFaces = mFaces.size(); 1.221 + mesh->mFaces = new aiFace[mesh->mNumFaces]; 1.222 + for( unsigned int a = 0; a < mesh->mNumFaces; a++) 1.223 + { 1.224 + const Face& inface = mFaces[a]; 1.225 + aiFace& outface = mesh->mFaces[a]; 1.226 + outface.mNumIndices = 3; 1.227 + outface.mIndices = new unsigned int[3]; 1.228 + outface.mIndices[0] = inface.mIndices[0]; 1.229 + outface.mIndices[1] = inface.mIndices[1]; 1.230 + outface.mIndices[2] = inface.mIndices[2]; 1.231 + 1.232 + // Compute per-face normals ... we don't want the bones to be smoothed ... they're built to visualize 1.233 + // the skeleton, so it's good if there's a visual difference to the rest of the geometry 1.234 + aiVector3D nor = ((mVertices[inface.mIndices[2]] - mVertices[inface.mIndices[0]]) ^ 1.235 + (mVertices[inface.mIndices[1]] - mVertices[inface.mIndices[0]])); 1.236 + 1.237 + if (nor.Length() < 1e-5f) /* ensure that FindInvalidData won't remove us ...*/ 1.238 + nor = aiVector3D(1.f,0.f,0.f); 1.239 + 1.240 + for (unsigned int n = 0; n < 3; ++n) 1.241 + mesh->mNormals[inface.mIndices[n]] = nor; 1.242 + } 1.243 + 1.244 + // add the bones 1.245 + mesh->mNumBones = mBones.size(); 1.246 + mesh->mBones = new aiBone*[mesh->mNumBones]; 1.247 + std::copy( mBones.begin(), mBones.end(), mesh->mBones); 1.248 + 1.249 + // default 1.250 + mesh->mMaterialIndex = 0; 1.251 + 1.252 + return mesh; 1.253 +} 1.254 + 1.255 +// ------------------------------------------------------------------------------------------------ 1.256 +// Creates a dummy material and returns it. 1.257 +aiMaterial* SkeletonMeshBuilder::CreateMaterial() 1.258 +{ 1.259 + aiMaterial* matHelper = new aiMaterial; 1.260 + 1.261 + // Name 1.262 + aiString matName( std::string( "SkeletonMaterial")); 1.263 + matHelper->AddProperty( &matName, AI_MATKEY_NAME); 1.264 + 1.265 + // Prevent backface culling 1.266 + const int no_cull = 1; 1.267 + matHelper->AddProperty(&no_cull,1,AI_MATKEY_TWOSIDED); 1.268 + 1.269 + return matHelper; 1.270 +}