vrshoot

annotate 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
rev   line source
nuclear@0 1 /*
nuclear@0 2 Open Asset Import Library (assimp)
nuclear@0 3 ----------------------------------------------------------------------
nuclear@0 4
nuclear@0 5 Copyright (c) 2006-2012, assimp team
nuclear@0 6 All rights reserved.
nuclear@0 7
nuclear@0 8 Redistribution and use of this software in source and binary forms,
nuclear@0 9 with or without modification, are permitted provided that the
nuclear@0 10 following conditions are met:
nuclear@0 11
nuclear@0 12 * Redistributions of source code must retain the above
nuclear@0 13 copyright notice, this list of conditions and the
nuclear@0 14 following disclaimer.
nuclear@0 15
nuclear@0 16 * Redistributions in binary form must reproduce the above
nuclear@0 17 copyright notice, this list of conditions and the
nuclear@0 18 following disclaimer in the documentation and/or other
nuclear@0 19 materials provided with the distribution.
nuclear@0 20
nuclear@0 21 * Neither the name of the assimp team, nor the names of its
nuclear@0 22 contributors may be used to endorse or promote products
nuclear@0 23 derived from this software without specific prior
nuclear@0 24 written permission of the assimp team.
nuclear@0 25
nuclear@0 26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 37
nuclear@0 38 ----------------------------------------------------------------------
nuclear@0 39 */
nuclear@0 40
nuclear@0 41 /** @file SkeletonMeshBuilder.cpp
nuclear@0 42 * @brief Implementation of a little class to construct a dummy mesh for a skeleton
nuclear@0 43 */
nuclear@0 44
nuclear@0 45 #include "AssimpPCH.h"
nuclear@0 46 #include "assimp/scene.h"
nuclear@0 47 #include "SkeletonMeshBuilder.h"
nuclear@0 48
nuclear@0 49 using namespace Assimp;
nuclear@0 50
nuclear@0 51 // ------------------------------------------------------------------------------------------------
nuclear@0 52 // The constructor processes the given scene and adds a mesh there.
nuclear@0 53 SkeletonMeshBuilder::SkeletonMeshBuilder( aiScene* pScene, aiNode* root, bool bKnobsOnly)
nuclear@0 54 {
nuclear@0 55 // nothing to do if there's mesh data already present at the scene
nuclear@0 56 if( pScene->mNumMeshes > 0 || pScene->mRootNode == NULL)
nuclear@0 57 return;
nuclear@0 58
nuclear@0 59 if (!root)
nuclear@0 60 root = pScene->mRootNode;
nuclear@0 61
nuclear@0 62 mKnobsOnly = bKnobsOnly;
nuclear@0 63
nuclear@0 64 // build some faces around each node
nuclear@0 65 CreateGeometry( root );
nuclear@0 66
nuclear@0 67 // create a mesh to hold all the generated faces
nuclear@0 68 pScene->mNumMeshes = 1;
nuclear@0 69 pScene->mMeshes = new aiMesh*[1];
nuclear@0 70 pScene->mMeshes[0] = CreateMesh();
nuclear@0 71 // and install it at the root node
nuclear@0 72 root->mNumMeshes = 1;
nuclear@0 73 root->mMeshes = new unsigned int[1];
nuclear@0 74 root->mMeshes[0] = 0;
nuclear@0 75
nuclear@0 76 // create a dummy material for the mesh
nuclear@0 77 pScene->mNumMaterials = 1;
nuclear@0 78 pScene->mMaterials = new aiMaterial*[1];
nuclear@0 79 pScene->mMaterials[0] = CreateMaterial();
nuclear@0 80 }
nuclear@0 81
nuclear@0 82 // ------------------------------------------------------------------------------------------------
nuclear@0 83 // Recursively builds a simple mesh representation for the given node
nuclear@0 84 void SkeletonMeshBuilder::CreateGeometry( const aiNode* pNode)
nuclear@0 85 {
nuclear@0 86 // add a joint entry for the node.
nuclear@0 87 const unsigned int vertexStartIndex = mVertices.size();
nuclear@0 88
nuclear@0 89 // now build the geometry.
nuclear@0 90 if( pNode->mNumChildren > 0 && !mKnobsOnly)
nuclear@0 91 {
nuclear@0 92 // If the node has children, we build little pointers to each of them
nuclear@0 93 for( unsigned int a = 0; a < pNode->mNumChildren; a++)
nuclear@0 94 {
nuclear@0 95 // find a suitable coordinate system
nuclear@0 96 const aiMatrix4x4& childTransform = pNode->mChildren[a]->mTransformation;
nuclear@0 97 aiVector3D childpos( childTransform.a4, childTransform.b4, childTransform.c4);
nuclear@0 98 float distanceToChild = childpos.Length();
nuclear@0 99 if( distanceToChild < 0.0001f)
nuclear@0 100 continue;
nuclear@0 101 aiVector3D up = aiVector3D( childpos).Normalize();
nuclear@0 102
nuclear@0 103 aiVector3D orth( 1.0f, 0.0f, 0.0f);
nuclear@0 104 if( fabs( orth * up) > 0.99f)
nuclear@0 105 orth.Set( 0.0f, 1.0f, 0.0f);
nuclear@0 106
nuclear@0 107 aiVector3D front = (up ^ orth).Normalize();
nuclear@0 108 aiVector3D side = (front ^ up).Normalize();
nuclear@0 109
nuclear@0 110 unsigned int localVertexStart = mVertices.size();
nuclear@0 111 mVertices.push_back( -front * distanceToChild * 0.1f);
nuclear@0 112 mVertices.push_back( childpos);
nuclear@0 113 mVertices.push_back( -side * distanceToChild * 0.1f);
nuclear@0 114 mVertices.push_back( -side * distanceToChild * 0.1f);
nuclear@0 115 mVertices.push_back( childpos);
nuclear@0 116 mVertices.push_back( front * distanceToChild * 0.1f);
nuclear@0 117 mVertices.push_back( front * distanceToChild * 0.1f);
nuclear@0 118 mVertices.push_back( childpos);
nuclear@0 119 mVertices.push_back( side * distanceToChild * 0.1f);
nuclear@0 120 mVertices.push_back( side * distanceToChild * 0.1f);
nuclear@0 121 mVertices.push_back( childpos);
nuclear@0 122 mVertices.push_back( -front * distanceToChild * 0.1f);
nuclear@0 123
nuclear@0 124 mFaces.push_back( Face( localVertexStart + 0, localVertexStart + 1, localVertexStart + 2));
nuclear@0 125 mFaces.push_back( Face( localVertexStart + 3, localVertexStart + 4, localVertexStart + 5));
nuclear@0 126 mFaces.push_back( Face( localVertexStart + 6, localVertexStart + 7, localVertexStart + 8));
nuclear@0 127 mFaces.push_back( Face( localVertexStart + 9, localVertexStart + 10, localVertexStart + 11));
nuclear@0 128 }
nuclear@0 129 }
nuclear@0 130 else
nuclear@0 131 {
nuclear@0 132 // if the node has no children, it's an end node. Put a little knob there instead
nuclear@0 133 aiVector3D ownpos( pNode->mTransformation.a4, pNode->mTransformation.b4, pNode->mTransformation.c4);
nuclear@0 134 float sizeEstimate = ownpos.Length() * 0.18f;
nuclear@0 135
nuclear@0 136 mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f));
nuclear@0 137 mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f));
nuclear@0 138 mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate));
nuclear@0 139 mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f));
nuclear@0 140 mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f));
nuclear@0 141 mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate));
nuclear@0 142 mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f));
nuclear@0 143 mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f));
nuclear@0 144 mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate));
nuclear@0 145 mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f));
nuclear@0 146 mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f));
nuclear@0 147 mVertices.push_back( aiVector3D( 0.0f, 0.0f, -sizeEstimate));
nuclear@0 148
nuclear@0 149 mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f));
nuclear@0 150 mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate));
nuclear@0 151 mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f));
nuclear@0 152 mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f));
nuclear@0 153 mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate));
nuclear@0 154 mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f));
nuclear@0 155 mVertices.push_back( aiVector3D( sizeEstimate, 0.0f, 0.0f));
nuclear@0 156 mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate));
nuclear@0 157 mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f));
nuclear@0 158 mVertices.push_back( aiVector3D( 0.0f, -sizeEstimate, 0.0f));
nuclear@0 159 mVertices.push_back( aiVector3D( 0.0f, 0.0f, sizeEstimate));
nuclear@0 160 mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f));
nuclear@0 161
nuclear@0 162 mFaces.push_back( Face( vertexStartIndex + 0, vertexStartIndex + 1, vertexStartIndex + 2));
nuclear@0 163 mFaces.push_back( Face( vertexStartIndex + 3, vertexStartIndex + 4, vertexStartIndex + 5));
nuclear@0 164 mFaces.push_back( Face( vertexStartIndex + 6, vertexStartIndex + 7, vertexStartIndex + 8));
nuclear@0 165 mFaces.push_back( Face( vertexStartIndex + 9, vertexStartIndex + 10, vertexStartIndex + 11));
nuclear@0 166 mFaces.push_back( Face( vertexStartIndex + 12, vertexStartIndex + 13, vertexStartIndex + 14));
nuclear@0 167 mFaces.push_back( Face( vertexStartIndex + 15, vertexStartIndex + 16, vertexStartIndex + 17));
nuclear@0 168 mFaces.push_back( Face( vertexStartIndex + 18, vertexStartIndex + 19, vertexStartIndex + 20));
nuclear@0 169 mFaces.push_back( Face( vertexStartIndex + 21, vertexStartIndex + 22, vertexStartIndex + 23));
nuclear@0 170 }
nuclear@0 171
nuclear@0 172 unsigned int numVertices = mVertices.size() - vertexStartIndex;
nuclear@0 173 if( numVertices > 0)
nuclear@0 174 {
nuclear@0 175 // create a bone affecting all the newly created vertices
nuclear@0 176 aiBone* bone = new aiBone;
nuclear@0 177 mBones.push_back( bone);
nuclear@0 178 bone->mName = pNode->mName;
nuclear@0 179
nuclear@0 180 // calculate the bone offset matrix by concatenating the inverse transformations of all parents
nuclear@0 181 bone->mOffsetMatrix = aiMatrix4x4( pNode->mTransformation).Inverse();
nuclear@0 182 for( aiNode* parent = pNode->mParent; parent != NULL; parent = parent->mParent)
nuclear@0 183 bone->mOffsetMatrix = aiMatrix4x4( parent->mTransformation).Inverse() * bone->mOffsetMatrix;
nuclear@0 184
nuclear@0 185 // add all the vertices to the bone's influences
nuclear@0 186 bone->mNumWeights = numVertices;
nuclear@0 187 bone->mWeights = new aiVertexWeight[numVertices];
nuclear@0 188 for( unsigned int a = 0; a < numVertices; a++)
nuclear@0 189 bone->mWeights[a] = aiVertexWeight( vertexStartIndex + a, 1.0f);
nuclear@0 190
nuclear@0 191 // HACK: (thom) transform all vertices to the bone's local space. Should be done before adding
nuclear@0 192 // them to the array, but I'm tired now and I'm annoyed.
nuclear@0 193 aiMatrix4x4 boneToMeshTransform = aiMatrix4x4( bone->mOffsetMatrix).Inverse();
nuclear@0 194 for( unsigned int a = vertexStartIndex; a < mVertices.size(); a++)
nuclear@0 195 mVertices[a] = boneToMeshTransform * mVertices[a];
nuclear@0 196 }
nuclear@0 197
nuclear@0 198 // and finally recurse into the children list
nuclear@0 199 for( unsigned int a = 0; a < pNode->mNumChildren; a++)
nuclear@0 200 CreateGeometry( pNode->mChildren[a]);
nuclear@0 201 }
nuclear@0 202
nuclear@0 203 // ------------------------------------------------------------------------------------------------
nuclear@0 204 // Creates the mesh from the internally accumulated stuff and returns it.
nuclear@0 205 aiMesh* SkeletonMeshBuilder::CreateMesh()
nuclear@0 206 {
nuclear@0 207 aiMesh* mesh = new aiMesh();
nuclear@0 208
nuclear@0 209 // add points
nuclear@0 210 mesh->mNumVertices = mVertices.size();
nuclear@0 211 mesh->mVertices = new aiVector3D[mesh->mNumVertices];
nuclear@0 212 std::copy( mVertices.begin(), mVertices.end(), mesh->mVertices);
nuclear@0 213
nuclear@0 214 mesh->mNormals = new aiVector3D[mesh->mNumVertices];
nuclear@0 215
nuclear@0 216 // add faces
nuclear@0 217 mesh->mNumFaces = mFaces.size();
nuclear@0 218 mesh->mFaces = new aiFace[mesh->mNumFaces];
nuclear@0 219 for( unsigned int a = 0; a < mesh->mNumFaces; a++)
nuclear@0 220 {
nuclear@0 221 const Face& inface = mFaces[a];
nuclear@0 222 aiFace& outface = mesh->mFaces[a];
nuclear@0 223 outface.mNumIndices = 3;
nuclear@0 224 outface.mIndices = new unsigned int[3];
nuclear@0 225 outface.mIndices[0] = inface.mIndices[0];
nuclear@0 226 outface.mIndices[1] = inface.mIndices[1];
nuclear@0 227 outface.mIndices[2] = inface.mIndices[2];
nuclear@0 228
nuclear@0 229 // Compute per-face normals ... we don't want the bones to be smoothed ... they're built to visualize
nuclear@0 230 // the skeleton, so it's good if there's a visual difference to the rest of the geometry
nuclear@0 231 aiVector3D nor = ((mVertices[inface.mIndices[2]] - mVertices[inface.mIndices[0]]) ^
nuclear@0 232 (mVertices[inface.mIndices[1]] - mVertices[inface.mIndices[0]]));
nuclear@0 233
nuclear@0 234 if (nor.Length() < 1e-5f) /* ensure that FindInvalidData won't remove us ...*/
nuclear@0 235 nor = aiVector3D(1.f,0.f,0.f);
nuclear@0 236
nuclear@0 237 for (unsigned int n = 0; n < 3; ++n)
nuclear@0 238 mesh->mNormals[inface.mIndices[n]] = nor;
nuclear@0 239 }
nuclear@0 240
nuclear@0 241 // add the bones
nuclear@0 242 mesh->mNumBones = mBones.size();
nuclear@0 243 mesh->mBones = new aiBone*[mesh->mNumBones];
nuclear@0 244 std::copy( mBones.begin(), mBones.end(), mesh->mBones);
nuclear@0 245
nuclear@0 246 // default
nuclear@0 247 mesh->mMaterialIndex = 0;
nuclear@0 248
nuclear@0 249 return mesh;
nuclear@0 250 }
nuclear@0 251
nuclear@0 252 // ------------------------------------------------------------------------------------------------
nuclear@0 253 // Creates a dummy material and returns it.
nuclear@0 254 aiMaterial* SkeletonMeshBuilder::CreateMaterial()
nuclear@0 255 {
nuclear@0 256 aiMaterial* matHelper = new aiMaterial;
nuclear@0 257
nuclear@0 258 // Name
nuclear@0 259 aiString matName( std::string( "SkeletonMaterial"));
nuclear@0 260 matHelper->AddProperty( &matName, AI_MATKEY_NAME);
nuclear@0 261
nuclear@0 262 // Prevent backface culling
nuclear@0 263 const int no_cull = 1;
nuclear@0 264 matHelper->AddProperty(&no_cull,1,AI_MATKEY_TWOSIDED);
nuclear@0 265
nuclear@0 266 return matHelper;
nuclear@0 267 }