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 }
|