1 | //////////////////////////////////////////////////////////////////////////////// |
---|
2 | // mesh.cpp |
---|
3 | // Author : Francesco Giordana |
---|
4 | // Start Date : January 13, 2005 |
---|
5 | // Copyright : (C) 2006 by Francesco Giordana |
---|
6 | // Email : fra.giordana@tiscali.it |
---|
7 | //////////////////////////////////////////////////////////////////////////////// |
---|
8 | |
---|
9 | /********************************************************************************* |
---|
10 | * * |
---|
11 | * This program is free software; you can redistribute it and/or modify * |
---|
12 | * it under the terms of the GNU Lesser General Public License as published by * |
---|
13 | * the Free Software Foundation; either version 2 of the License, or * |
---|
14 | * (at your option) any later version. * |
---|
15 | * * |
---|
16 | **********************************************************************************/ |
---|
17 | |
---|
18 | #include "mesh.h" |
---|
19 | #include <maya/MFnMatrixData.h> |
---|
20 | |
---|
21 | namespace OgreMayaExporter |
---|
22 | { |
---|
23 | /***** Class Mesh *****/ |
---|
24 | // constructor |
---|
25 | Mesh::Mesh(const MString& name) |
---|
26 | { |
---|
27 | m_name = name; |
---|
28 | m_numTriangles = 0; |
---|
29 | m_pSkeleton = NULL; |
---|
30 | m_sharedGeom.vertices.clear(); |
---|
31 | m_sharedGeom.dagMap.clear(); |
---|
32 | m_vertexClips.clear(); |
---|
33 | m_BSClips.clear(); |
---|
34 | } |
---|
35 | |
---|
36 | // destructor |
---|
37 | Mesh::~Mesh() |
---|
38 | { |
---|
39 | clear(); |
---|
40 | } |
---|
41 | |
---|
42 | // clear data |
---|
43 | void Mesh::clear() |
---|
44 | { |
---|
45 | int i; |
---|
46 | m_name = ""; |
---|
47 | m_numTriangles = 0; |
---|
48 | for (i=0; i<m_submeshes.size(); i++) |
---|
49 | delete m_submeshes[i]; |
---|
50 | for (i=0; i<m_sharedGeom.dagMap.size(); i++) |
---|
51 | { |
---|
52 | if (m_sharedGeom.dagMap[i].pBlendShape) |
---|
53 | delete m_sharedGeom.dagMap[i].pBlendShape; |
---|
54 | } |
---|
55 | m_sharedGeom.vertices.clear(); |
---|
56 | m_sharedGeom.dagMap.clear(); |
---|
57 | m_vertexClips.clear(); |
---|
58 | m_BSClips.clear(); |
---|
59 | m_uvsets.clear(); |
---|
60 | m_submeshes.clear(); |
---|
61 | if (m_pSkeleton) |
---|
62 | delete m_pSkeleton; |
---|
63 | m_pSkeleton = NULL; |
---|
64 | } |
---|
65 | |
---|
66 | // get pointer to linked skeleton |
---|
67 | Skeleton* Mesh::getSkeleton() |
---|
68 | { |
---|
69 | return m_pSkeleton; |
---|
70 | } |
---|
71 | |
---|
72 | /******************************************************************************* |
---|
73 | * Load mesh data from a Maya node * |
---|
74 | *******************************************************************************/ |
---|
75 | MStatus Mesh::load(const MDagPath& meshDag,ParamList ¶ms) |
---|
76 | { |
---|
77 | MStatus stat; |
---|
78 | // Check that given DagPath corresponds to a mesh node |
---|
79 | if (!meshDag.hasFn(MFn::kMesh)) |
---|
80 | return MS::kFailure; |
---|
81 | |
---|
82 | // Set mesh name |
---|
83 | m_name = "mayaExport"; |
---|
84 | |
---|
85 | // Initialise temporary variables |
---|
86 | newvertices.clear(); |
---|
87 | newweights.clear(); |
---|
88 | newjointIds.clear(); |
---|
89 | newuvsets.clear(); |
---|
90 | newpoints.clear(); |
---|
91 | newnormals.clear(); |
---|
92 | params.currentRootJoints.clear(); |
---|
93 | opposite = false; |
---|
94 | shaders.clear(); |
---|
95 | shaderPolygonMapping.clear(); |
---|
96 | polygonSets.clear(); |
---|
97 | pSkinCluster = NULL; |
---|
98 | pBlendShape = NULL; |
---|
99 | |
---|
100 | // Get mesh uvsets |
---|
101 | stat = getUVSets(meshDag); |
---|
102 | if (stat != MS::kSuccess) |
---|
103 | { |
---|
104 | std::cout << "Error retrieving uvsets for current mesh\n"; |
---|
105 | std::cout.flush(); |
---|
106 | } |
---|
107 | // Get linked skin cluster |
---|
108 | stat = getSkinCluster(meshDag,params); |
---|
109 | if (stat != MS::kSuccess) |
---|
110 | { |
---|
111 | std::cout << "Error retrieving skin cluster linked to current mesh\n"; |
---|
112 | std::cout.flush(); |
---|
113 | } |
---|
114 | // Get linked blend shape deformer |
---|
115 | stat = getBlendShapeDeformer(meshDag,params); |
---|
116 | if (stat != MS::kSuccess) |
---|
117 | { |
---|
118 | std::cout << "Error retrieving blend shape deformer linked to current mesh\n"; |
---|
119 | std::cout.flush(); |
---|
120 | } |
---|
121 | // Get connected shaders |
---|
122 | stat = getShaders(meshDag); |
---|
123 | if (stat != MS::kSuccess) |
---|
124 | { |
---|
125 | std::cout << "Error getting shaders connected to current mesh\n"; |
---|
126 | std::cout.flush(); |
---|
127 | } |
---|
128 | // Get vertex data |
---|
129 | stat = getVertices(meshDag,params); |
---|
130 | if (stat != MS::kSuccess) |
---|
131 | { |
---|
132 | std::cout << "Error retrieving vertex data for current mesh\n"; |
---|
133 | std::cout.flush(); |
---|
134 | } |
---|
135 | // Get vertex bone weights |
---|
136 | if (pSkinCluster) |
---|
137 | { |
---|
138 | getVertexBoneWeights(meshDag,params); |
---|
139 | if (stat != MS::kSuccess) |
---|
140 | { |
---|
141 | std::cout << "Error retrieving veretex bone assignements for current mesh\n"; |
---|
142 | std::cout.flush(); |
---|
143 | } |
---|
144 | } |
---|
145 | // Get faces data |
---|
146 | stat = getFaces(meshDag,params); |
---|
147 | if (stat != MS::kSuccess) |
---|
148 | { |
---|
149 | std::cout << "Error retrieving faces data for current mesh\n"; |
---|
150 | std::cout.flush(); |
---|
151 | } |
---|
152 | // Build shared geometry |
---|
153 | if (params.useSharedGeom) |
---|
154 | { |
---|
155 | stat = buildSharedGeometry(meshDag,params); |
---|
156 | if (stat != MS::kSuccess) |
---|
157 | { |
---|
158 | std::cout << "Error building shared geometry for current mesh\n"; |
---|
159 | std::cout.flush(); |
---|
160 | } |
---|
161 | } |
---|
162 | // Create submeshes (a different submesh for every different shader linked to the mesh) |
---|
163 | stat = createSubmeshes(meshDag,params); |
---|
164 | if (stat != MS::kSuccess) |
---|
165 | { |
---|
166 | std::cout << "Error creating submeshes for current mesh\n"; |
---|
167 | std::cout.flush(); |
---|
168 | } |
---|
169 | // Free up memory |
---|
170 | newvertices.clear(); |
---|
171 | newweights.clear(); |
---|
172 | newjointIds.clear(); |
---|
173 | newpoints.clear(); |
---|
174 | newnormals.clear(); |
---|
175 | newuvsets.clear(); |
---|
176 | shaders.clear(); |
---|
177 | shaderPolygonMapping.clear(); |
---|
178 | polygonSets.clear(); |
---|
179 | if (pSkinCluster) |
---|
180 | delete pSkinCluster; |
---|
181 | pBlendShape = NULL; |
---|
182 | |
---|
183 | return MS::kSuccess; |
---|
184 | } |
---|
185 | |
---|
186 | |
---|
187 | /******************************************************************************* |
---|
188 | * Load mesh animations from Maya * |
---|
189 | *******************************************************************************/ |
---|
190 | // Load vertex animations |
---|
191 | MStatus Mesh::loadAnims(ParamList& params) |
---|
192 | { |
---|
193 | MStatus stat; |
---|
194 | int i; |
---|
195 | // save current time for later restore |
---|
196 | MTime curTime = MAnimControl::currentTime(); |
---|
197 | std::cout << "Loading vertex animations...\n"; |
---|
198 | std::cout.flush(); |
---|
199 | // clear animations data |
---|
200 | m_vertexClips.clear(); |
---|
201 | // load the requested clips |
---|
202 | for (i=0; i<params.vertClipList.size(); i++) |
---|
203 | { |
---|
204 | std::cout << "Loading clip " << params.vertClipList[i].name.asChar() << "\n"; |
---|
205 | std::cout.flush(); |
---|
206 | stat = loadClip(params.vertClipList[i].name,params.vertClipList[i].start, |
---|
207 | params.vertClipList[i].stop,params.vertClipList[i].rate,params); |
---|
208 | if (stat == MS::kSuccess) |
---|
209 | { |
---|
210 | std::cout << "Clip successfully loaded\n"; |
---|
211 | std::cout.flush(); |
---|
212 | } |
---|
213 | else |
---|
214 | { |
---|
215 | std::cout << "Failed loading clip\n"; |
---|
216 | std::cout.flush(); |
---|
217 | } |
---|
218 | } |
---|
219 | //restore current time |
---|
220 | MAnimControl::setCurrentTime(curTime); |
---|
221 | return MS::kSuccess; |
---|
222 | } |
---|
223 | |
---|
224 | |
---|
225 | |
---|
226 | // Load blend shape deformers |
---|
227 | MStatus Mesh::loadBlendShapes(ParamList ¶ms) |
---|
228 | { |
---|
229 | MStatus stat; |
---|
230 | int i; |
---|
231 | std::cout << "Loading blend shape poses...\n"; |
---|
232 | std::cout.flush(); |
---|
233 | // Set envelopes of all blend shape deformers to 0 |
---|
234 | if (params.useSharedGeom) |
---|
235 | { |
---|
236 | for (i=0; i<m_sharedGeom.dagMap.size(); i++) |
---|
237 | { |
---|
238 | dagInfo di = m_sharedGeom.dagMap[i]; |
---|
239 | if (di.pBlendShape) |
---|
240 | di.pBlendShape->setEnvelope(0); |
---|
241 | } |
---|
242 | } |
---|
243 | else |
---|
244 | { |
---|
245 | for (i=0; i<m_submeshes.size(); i++) |
---|
246 | { |
---|
247 | Submesh* pSubmesh = m_submeshes[i]; |
---|
248 | if (pSubmesh->m_pBlendShape) |
---|
249 | pSubmesh->m_pBlendShape->setEnvelope(0); |
---|
250 | } |
---|
251 | } |
---|
252 | // Get the blend shape poses |
---|
253 | if (params.useSharedGeom) |
---|
254 | { |
---|
255 | for (i=0; i<m_sharedGeom.dagMap.size(); i++) |
---|
256 | { |
---|
257 | dagInfo di = m_sharedGeom.dagMap[i]; |
---|
258 | if (di.pBlendShape) |
---|
259 | di.pBlendShape->loadPoses(di.dagPath,params,m_sharedGeom.vertices,di.numVertices,di.offset); |
---|
260 | } |
---|
261 | } |
---|
262 | else |
---|
263 | { |
---|
264 | for (i=0; i<m_submeshes.size(); i++) |
---|
265 | { |
---|
266 | Submesh* pSubmesh = m_submeshes[i]; |
---|
267 | if (pSubmesh->m_pBlendShape) |
---|
268 | pSubmesh->m_pBlendShape->loadPoses(pSubmesh->m_dagPath,params,pSubmesh->m_vertices, |
---|
269 | pSubmesh->m_vertices.size(),0,i); |
---|
270 | } |
---|
271 | } |
---|
272 | // Restore blend shape deformers original envelopes |
---|
273 | if (params.useSharedGeom) |
---|
274 | { |
---|
275 | for (i=0; i<m_sharedGeom.dagMap.size(); i++) |
---|
276 | { |
---|
277 | dagInfo di = m_sharedGeom.dagMap[i]; |
---|
278 | if (di.pBlendShape) |
---|
279 | di.pBlendShape->restoreEnvelope(); |
---|
280 | } |
---|
281 | } |
---|
282 | else |
---|
283 | { |
---|
284 | for (i=0; i<m_submeshes.size(); i++) |
---|
285 | { |
---|
286 | Submesh* pSubmesh = m_submeshes[i]; |
---|
287 | if (pSubmesh->m_pBlendShape) |
---|
288 | pSubmesh->m_pBlendShape->restoreEnvelope(); |
---|
289 | } |
---|
290 | } |
---|
291 | // Read blend shape animations |
---|
292 | if (params.exportBSAnims) |
---|
293 | { |
---|
294 | stat = loadBlendShapeAnimations(params); |
---|
295 | } |
---|
296 | return MS::kSuccess; |
---|
297 | } |
---|
298 | |
---|
299 | // Load blend shape animations |
---|
300 | MStatus Mesh::loadBlendShapeAnimations(ParamList& params) |
---|
301 | { |
---|
302 | int i,j,k; |
---|
303 | std::cout << "Loading blend shape animations...\n"; |
---|
304 | std::cout.flush(); |
---|
305 | // Read the list of blend shape clips to export |
---|
306 | for (i=0; i<params.BSClipList.size(); i++) |
---|
307 | { |
---|
308 | int startPoseId = 0; |
---|
309 | clipInfo ci = params.BSClipList[i]; |
---|
310 | // Create a new animation for every clip |
---|
311 | Animation a; |
---|
312 | a.m_name = ci.name; |
---|
313 | a.m_length = ci.stop - ci.start; |
---|
314 | a.m_tracks.clear(); |
---|
315 | std::cout << "clip " << ci.name.asChar() << "\n"; |
---|
316 | // Read animation tracks from the blend shape deformer |
---|
317 | if (params.useSharedGeom) |
---|
318 | { |
---|
319 | // Create a track for each blend shape |
---|
320 | std::vector<Track> tracks; |
---|
321 | for (j=0; j<m_sharedGeom.dagMap.size(); j++) |
---|
322 | { |
---|
323 | dagInfo di = m_sharedGeom.dagMap[j]; |
---|
324 | if (di.pBlendShape) |
---|
325 | { |
---|
326 | Track t = di.pBlendShape->loadTrack(ci.start,ci.stop,ci.rate,params,startPoseId); |
---|
327 | tracks.push_back(t); |
---|
328 | startPoseId += di.pBlendShape->getPoses().size(); |
---|
329 | } |
---|
330 | } |
---|
331 | // Merge the tracks into a single track (shared geometry must have a single animation track) |
---|
332 | if (tracks.size() > 0) |
---|
333 | { |
---|
334 | Track newTrack; |
---|
335 | // Merge keyframes at the same time position from all tracks |
---|
336 | for (j=0; j<tracks[0].m_vertexKeyframes.size(); j++) |
---|
337 | { |
---|
338 | // Create a new keyframe |
---|
339 | vertexKeyframe newKeyframe; |
---|
340 | newKeyframe.time = tracks[0].m_vertexKeyframes[j].time; |
---|
341 | // Get keyframe at current position from all tracks |
---|
342 | for (k=0; k<tracks.size(); k++) |
---|
343 | { |
---|
344 | vertexKeyframe* pSrcKeyframe = &tracks[k].m_vertexKeyframes[j]; |
---|
345 | int pri; |
---|
346 | // Add pose references from this keyframe to the new keyframe for the joined track |
---|
347 | for (pri=0; pri<pSrcKeyframe->poserefs.size(); pri++) |
---|
348 | { |
---|
349 | // Create a new pose reference |
---|
350 | vertexPoseRef poseref; |
---|
351 | // Copy pose reference settings from source keyframe |
---|
352 | poseref.poseIndex = pSrcKeyframe->poserefs[pri].poseIndex; |
---|
353 | poseref.poseWeight = pSrcKeyframe->poserefs[pri].poseWeight; |
---|
354 | // Add the new pose reference to the new keyframe |
---|
355 | newKeyframe.poserefs.push_back(poseref); |
---|
356 | } |
---|
357 | } |
---|
358 | // Add the keyframe to the new joined track |
---|
359 | newTrack.m_vertexKeyframes.push_back(newKeyframe); |
---|
360 | } |
---|
361 | // Add the joined track to current animation clip |
---|
362 | a.addTrack(newTrack); |
---|
363 | } |
---|
364 | } |
---|
365 | else |
---|
366 | { |
---|
367 | // Create a track for each submesh |
---|
368 | std::vector<Track> tracks; |
---|
369 | for (j=0; j<m_submeshes.size(); j++) |
---|
370 | { |
---|
371 | Submesh* pSubmesh = m_submeshes[j]; |
---|
372 | if (pSubmesh->m_pBlendShape) |
---|
373 | { |
---|
374 | Track t = pSubmesh->m_pBlendShape->loadTrack(ci.start,ci.stop,ci.rate,params,startPoseId); |
---|
375 | a.addTrack(t); |
---|
376 | startPoseId += pSubmesh->m_pBlendShape->getPoses().size(); |
---|
377 | } |
---|
378 | } |
---|
379 | } |
---|
380 | std::cout << "length: " << a.m_length << "\n"; |
---|
381 | std::cout << "num keyframes: " << a.m_tracks[0].m_vertexKeyframes.size() << "\n"; |
---|
382 | std::cout.flush(); |
---|
383 | m_BSClips.push_back(a); |
---|
384 | } |
---|
385 | return MS::kSuccess; |
---|
386 | } |
---|
387 | /******************** Methods to parse geometry data from Maya ************************/ |
---|
388 | // Get uvsets info from the maya mesh |
---|
389 | MStatus Mesh::getUVSets(const MDagPath& meshDag) |
---|
390 | { |
---|
391 | MFnMesh mesh(meshDag); |
---|
392 | int i; |
---|
393 | MStatus stat; |
---|
394 | // Get uv texture coordinate sets' names |
---|
395 | if (mesh.numUVSets() > 0) |
---|
396 | { |
---|
397 | stat = mesh.getUVSetNames(newuvsets); |
---|
398 | if (MS::kSuccess != stat) |
---|
399 | { |
---|
400 | std::cout << "Error retrieving UV sets names\n"; |
---|
401 | std::cout.flush(); |
---|
402 | return MS::kFailure; |
---|
403 | } |
---|
404 | } |
---|
405 | // Save uvsets info |
---|
406 | for (i=m_uvsets.size(); i<newuvsets.length(); i++) |
---|
407 | { |
---|
408 | uvset uv; |
---|
409 | uv.size = 2; |
---|
410 | m_uvsets.push_back(uv); |
---|
411 | } |
---|
412 | return MS::kSuccess; |
---|
413 | } |
---|
414 | |
---|
415 | |
---|
416 | // Get skin cluster linked to the maya mesh |
---|
417 | MStatus Mesh::getSkinCluster(const MDagPath &meshDag, ParamList ¶ms) |
---|
418 | { |
---|
419 | MStatus stat; |
---|
420 | MFnMesh mesh(meshDag); |
---|
421 | pSkinCluster = NULL; |
---|
422 | if (params.exportVBA || params.exportSkeleton) |
---|
423 | { |
---|
424 | // get connected skin clusters (if present) |
---|
425 | MItDependencyNodes kDepNodeIt( MFn::kSkinClusterFilter ); |
---|
426 | for( ;!kDepNodeIt.isDone() && !pSkinCluster; kDepNodeIt.next()) |
---|
427 | { |
---|
428 | MObject kObject = kDepNodeIt.item(); |
---|
429 | pSkinCluster = new MFnSkinCluster(kObject); |
---|
430 | unsigned int uiNumGeometries = pSkinCluster->numOutputConnections(); |
---|
431 | unsigned int uiGeometry; |
---|
432 | for(uiGeometry = 0; uiGeometry < uiNumGeometries; ++uiGeometry ) |
---|
433 | { |
---|
434 | unsigned int uiIndex = pSkinCluster->indexForOutputConnection(uiGeometry); |
---|
435 | MObject kOutputObject = pSkinCluster->outputShapeAtIndex(uiIndex); |
---|
436 | if(kOutputObject == mesh.object()) |
---|
437 | { |
---|
438 | std::cout << "Found skin cluster " << pSkinCluster->name().asChar() << " for mesh " |
---|
439 | << mesh.name().asChar() << "\n"; |
---|
440 | std::cout.flush(); |
---|
441 | } |
---|
442 | else |
---|
443 | { |
---|
444 | delete pSkinCluster; |
---|
445 | pSkinCluster = NULL; |
---|
446 | } |
---|
447 | } |
---|
448 | } |
---|
449 | if (pSkinCluster) |
---|
450 | { |
---|
451 | // load the skeleton |
---|
452 | std::cout << "Loading skeleton data...\n"; |
---|
453 | std::cout.flush(); |
---|
454 | if (!m_pSkeleton) |
---|
455 | m_pSkeleton = new Skeleton(); |
---|
456 | stat = m_pSkeleton->load(pSkinCluster,params); |
---|
457 | if (MS::kSuccess != stat) |
---|
458 | { |
---|
459 | std::cout << "Error loading skeleton data\n"; |
---|
460 | std::cout.flush(); |
---|
461 | } |
---|
462 | else |
---|
463 | { |
---|
464 | std::cout << "OK\n"; |
---|
465 | std::cout.flush(); |
---|
466 | } |
---|
467 | } |
---|
468 | } |
---|
469 | return MS::kSuccess; |
---|
470 | } |
---|
471 | |
---|
472 | |
---|
473 | // Get blend shape deformer linked to the maya mesh |
---|
474 | MStatus Mesh::getBlendShapeDeformer(const MDagPath &meshDag, OgreMayaExporter::ParamList ¶ms) |
---|
475 | { |
---|
476 | MStatus stat; |
---|
477 | MFnMesh mesh(meshDag); |
---|
478 | if (params.exportBlendShapes) |
---|
479 | { |
---|
480 | // get connected blend shape deformer (if present) |
---|
481 | MItDependencyNodes kDepNodeIt( MFn::kBlendShape ); |
---|
482 | for( ;!kDepNodeIt.isDone() && !pBlendShape; kDepNodeIt.next()) |
---|
483 | { |
---|
484 | MObject kObject = kDepNodeIt.item(); |
---|
485 | MItDependencyGraph itGraph(kObject,MFn::kMesh,MItDependencyGraph::kDownstream,MItDependencyGraph::kDepthFirst); |
---|
486 | for (;!itGraph.isDone() && !pBlendShape; itGraph.next()) |
---|
487 | { |
---|
488 | MFnMesh connectedMesh(itGraph.thisNode()); |
---|
489 | if (connectedMesh.fullPathName() == mesh.fullPathName()) |
---|
490 | { |
---|
491 | pBlendShape = new BlendShape(); |
---|
492 | pBlendShape->load(kObject); |
---|
493 | std::cout << "Found blend shape deformer " << pBlendShape->getName().asChar() << " for mesh " |
---|
494 | << mesh.name().asChar() << "\n"; |
---|
495 | } |
---|
496 | } |
---|
497 | } |
---|
498 | } |
---|
499 | return MS::kSuccess; |
---|
500 | } |
---|
501 | // Get connected shaders |
---|
502 | MStatus Mesh::getShaders(const MDagPath& meshDag) |
---|
503 | { |
---|
504 | MStatus stat; |
---|
505 | MFnMesh mesh(meshDag); |
---|
506 | stat = mesh.getConnectedShaders(0,shaders,shaderPolygonMapping); |
---|
507 | std::cout.flush(); |
---|
508 | if (MS::kSuccess != stat) |
---|
509 | { |
---|
510 | std::cout << "Error getting connected shaders\n"; |
---|
511 | std::cout.flush(); |
---|
512 | return MS::kFailure; |
---|
513 | } |
---|
514 | std::cout << "Found " << shaders.length() << " connected shaders\n"; |
---|
515 | std::cout.flush(); |
---|
516 | if (shaders.length() <= 0) |
---|
517 | { |
---|
518 | std::cout << "No connected shaders, skipping mesh\n"; |
---|
519 | std::cout.flush(); |
---|
520 | return MS::kFailure; |
---|
521 | } |
---|
522 | // create a series of arrays of faces for each different submesh |
---|
523 | polygonSets.clear(); |
---|
524 | polygonSets.resize(shaders.length()); |
---|
525 | return MS::kSuccess; |
---|
526 | } |
---|
527 | |
---|
528 | |
---|
529 | // Get vertex data |
---|
530 | MStatus Mesh::getVertices(const MDagPath &meshDag, OgreMayaExporter::ParamList ¶ms) |
---|
531 | { |
---|
532 | int i; |
---|
533 | MFnMesh mesh(meshDag); |
---|
534 | // prepare vertex table |
---|
535 | newvertices.resize(mesh.numVertices()); |
---|
536 | newweights.resize(mesh.numVertices()); |
---|
537 | newjointIds.resize(mesh.numVertices()); |
---|
538 | for (i=0; i<newvertices.size(); i++) |
---|
539 | { |
---|
540 | newvertices[i].pointIdx = -1; |
---|
541 | newvertices[i].normalIdx = -1; |
---|
542 | newvertices[i].next = -2; |
---|
543 | } |
---|
544 | //get vertex positions from mesh |
---|
545 | if (params.exportWorldCoords || (pSkinCluster && params.exportSkeleton)) |
---|
546 | mesh.getPoints(newpoints,MSpace::kWorld); |
---|
547 | else |
---|
548 | mesh.getPoints(newpoints,MSpace::kTransform); |
---|
549 | //get list of normals from mesh data |
---|
550 | if (params.exportWorldCoords) |
---|
551 | mesh.getNormals(newnormals,MSpace::kWorld); |
---|
552 | else |
---|
553 | mesh.getNormals(newnormals,MSpace::kTransform); |
---|
554 | //check the "opposite" attribute to see if we have to flip normals |
---|
555 | mesh.findPlug("opposite",true).getValue(opposite); |
---|
556 | return MS::kSuccess; |
---|
557 | } |
---|
558 | |
---|
559 | |
---|
560 | // Get vertex bone assignements |
---|
561 | MStatus Mesh::getVertexBoneWeights(const MDagPath& meshDag, OgreMayaExporter::ParamList ¶ms) |
---|
562 | { |
---|
563 | int i,j,k; |
---|
564 | unsigned int numWeights; |
---|
565 | MStatus stat; |
---|
566 | std::cout << "Get vbas\n"; |
---|
567 | std::cout.flush(); |
---|
568 | MItGeometry iterGeom(meshDag); |
---|
569 | for (i=0; !iterGeom.isDone(); iterGeom.next(), i++) |
---|
570 | { |
---|
571 | MObject component = iterGeom.component(); |
---|
572 | MFloatArray vertexWeights; |
---|
573 | stat=pSkinCluster->getWeights(meshDag,component,vertexWeights,numWeights); |
---|
574 | /* //normalize vertex weights |
---|
575 | int widx; |
---|
576 | // first, truncate the weights to given precision |
---|
577 | long weightSum = 0; |
---|
578 | for (widx=0; widx < vertexWeights.length(); widx++) |
---|
579 | { |
---|
580 | long w = (long) (((float)vertexWeights[widx]) / ((float)PRECISION)); |
---|
581 | vertexWeights[widx] = w; |
---|
582 | weightSum += w; |
---|
583 | } |
---|
584 | // then divide by the sum of the weights to add up to 1 |
---|
585 | // (if there is at least one weight > 0) |
---|
586 | if (weightSum > 0) |
---|
587 | { |
---|
588 | float newSum = 0; |
---|
589 | for (widx=0; widx < numWeights; widx++) |
---|
590 | { |
---|
591 | long w = (long) ((float)vertexWeights[widx] / ((float)PRECISION)); |
---|
592 | w = (long) (((float)w) / ((float)weightSum)); |
---|
593 | vertexWeights[widx] = (float) (((long)w) * ((float)PRECISION)); |
---|
594 | newSum += vertexWeights[widx]; |
---|
595 | } |
---|
596 | if (newSum < 1.0f) |
---|
597 | vertexWeights[numWeights-1] += PRECISION; |
---|
598 | } |
---|
599 | // else set all weights to 0 |
---|
600 | else |
---|
601 | { |
---|
602 | for (widx=0; widx < numWeights; widx++) |
---|
603 | vertexWeights[widx] = 0; |
---|
604 | }*/ |
---|
605 | // save the normalized weights |
---|
606 | newweights[i]=vertexWeights; |
---|
607 | if (MS::kSuccess != stat) |
---|
608 | { |
---|
609 | std::cout << "Error retrieving vertex weights\n"; |
---|
610 | std::cout.flush(); |
---|
611 | } |
---|
612 | // get ids for the joints |
---|
613 | if (m_pSkeleton) |
---|
614 | { |
---|
615 | MDagPathArray influenceObjs; |
---|
616 | pSkinCluster->influenceObjects(influenceObjs,&stat); |
---|
617 | if (MS::kSuccess != stat) |
---|
618 | { |
---|
619 | std::cout << "Error retrieving influence objects for given skin cluster\n"; |
---|
620 | std::cout.flush(); |
---|
621 | } |
---|
622 | newjointIds[i].setLength(newweights[i].length()); |
---|
623 | for (j=0; j<influenceObjs.length(); j++) |
---|
624 | { |
---|
625 | bool foundJoint = false; |
---|
626 | MString partialPathName = influenceObjs[j].partialPathName(); |
---|
627 | for (k=0; k<m_pSkeleton->getJoints().size() && !foundJoint; k++) |
---|
628 | { |
---|
629 | if (partialPathName == m_pSkeleton->getJoints()[k].name) |
---|
630 | { |
---|
631 | foundJoint=true; |
---|
632 | newjointIds[i][j] = m_pSkeleton->getJoints()[k].id; |
---|
633 | } |
---|
634 | } |
---|
635 | } |
---|
636 | } |
---|
637 | } |
---|
638 | return MS::kSuccess; |
---|
639 | } |
---|
640 | |
---|
641 | |
---|
642 | // Get faces data |
---|
643 | MStatus Mesh::getFaces(const MDagPath &meshDag, ParamList ¶ms) |
---|
644 | { |
---|
645 | int i,j,k; |
---|
646 | MStatus stat; |
---|
647 | MFnMesh mesh(meshDag); |
---|
648 | // create an iterator to go through mesh polygons |
---|
649 | if (mesh.numPolygons() > 0) |
---|
650 | { |
---|
651 | std::cout << "Iterate over mesh polygons\n"; |
---|
652 | std::cout.flush(); |
---|
653 | MItMeshPolygon faceIter(mesh.object(),&stat); |
---|
654 | if (MS::kSuccess != stat) |
---|
655 | { |
---|
656 | std::cout << "Error accessing mesh polygons\n"; |
---|
657 | std::cout.flush(); |
---|
658 | return MS::kFailure; |
---|
659 | } |
---|
660 | std::cout << "num polygons = " << mesh.numPolygons() << "\n"; |
---|
661 | std::cout.flush(); |
---|
662 | // iterate over mesh polygons |
---|
663 | for (; !faceIter.isDone(); faceIter.next()) |
---|
664 | { |
---|
665 | int numTris=0; |
---|
666 | int iTris; |
---|
667 | bool different; |
---|
668 | int vtxIdx, nrmIdx; |
---|
669 | faceIter.numTriangles(numTris); |
---|
670 | // for every triangle composing current polygon extract triangle info |
---|
671 | for (iTris=0; iTris<numTris; iTris++) |
---|
672 | { |
---|
673 | MPointArray triPoints; |
---|
674 | MIntArray tempTriVertexIdx,triVertexIdx; |
---|
675 | int idx; |
---|
676 | // create a new face to store triangle info |
---|
677 | face newFace; |
---|
678 | // extract triangle vertex indices |
---|
679 | faceIter.getTriangle(iTris,triPoints,tempTriVertexIdx); |
---|
680 | // convert indices to face-relative indices |
---|
681 | MIntArray polyIndices; |
---|
682 | faceIter.getVertices(polyIndices); |
---|
683 | unsigned int iPoly, iObj; |
---|
684 | for (iObj=0; iObj < tempTriVertexIdx.length(); ++iObj) |
---|
685 | { |
---|
686 | // iPoly is face-relative vertex index |
---|
687 | for (iPoly=0; iPoly < polyIndices.length(); ++iPoly) |
---|
688 | { |
---|
689 | if (tempTriVertexIdx[iObj] == polyIndices[iPoly]) |
---|
690 | { |
---|
691 | triVertexIdx.append(iPoly); |
---|
692 | break; |
---|
693 | } |
---|
694 | } |
---|
695 | } |
---|
696 | // iterate over triangle's vertices |
---|
697 | for (i=0; i<3; i++) |
---|
698 | { |
---|
699 | different = true; |
---|
700 | vtxIdx = faceIter.vertexIndex(triVertexIdx[i],&stat); |
---|
701 | if (stat != MS::kSuccess) |
---|
702 | { |
---|
703 | std::cout << "Could not access vertex position\n"; |
---|
704 | std::cout.flush(); |
---|
705 | } |
---|
706 | nrmIdx = faceIter.normalIndex(triVertexIdx[i],&stat); |
---|
707 | if (stat != MS::kSuccess) |
---|
708 | { |
---|
709 | std::cout << "Could not access vertex normal\n"; |
---|
710 | std::cout.flush(); |
---|
711 | } |
---|
712 | |
---|
713 | // get vertex color |
---|
714 | MColor color; |
---|
715 | if (faceIter.hasColor(triVertexIdx[i])) |
---|
716 | { |
---|
717 | stat = faceIter.getColor(color,triVertexIdx[i]); |
---|
718 | if (MS::kSuccess != stat) |
---|
719 | { |
---|
720 | color = MColor(1,1,1,1); |
---|
721 | } |
---|
722 | if (color.r > 1) |
---|
723 | color.r = 1; |
---|
724 | else if (color.r < PRECISION) |
---|
725 | color.r = 0; |
---|
726 | if (color.g > 1) |
---|
727 | color.g = 1; |
---|
728 | else if (color.g < PRECISION) |
---|
729 | color.g = 0; |
---|
730 | if (color.b > 1) |
---|
731 | color.b = 1; |
---|
732 | else if (color.b < PRECISION) |
---|
733 | color.b = 0; |
---|
734 | if (color.a > 1) |
---|
735 | color.a = 1; |
---|
736 | else if (color.a < PRECISION) |
---|
737 | color.a = 0; |
---|
738 | } |
---|
739 | else |
---|
740 | { |
---|
741 | color = MColor(1,1,1,1); |
---|
742 | } |
---|
743 | if (newvertices[vtxIdx].next == -2) // first time we encounter a vertex in this position |
---|
744 | { |
---|
745 | // save vertex position |
---|
746 | newpoints[vtxIdx].cartesianize(); |
---|
747 | newvertices[vtxIdx].pointIdx = vtxIdx; |
---|
748 | // save vertex normal |
---|
749 | newvertices[vtxIdx].normalIdx = nrmIdx; |
---|
750 | // save vertex colour |
---|
751 | newvertices[vtxIdx].r = color.r; |
---|
752 | newvertices[vtxIdx].g = color.g; |
---|
753 | newvertices[vtxIdx].b = color.b; |
---|
754 | newvertices[vtxIdx].a = color.a; |
---|
755 | // save vertex texture coordinates |
---|
756 | newvertices[vtxIdx].u.resize(newuvsets.length()); |
---|
757 | newvertices[vtxIdx].v.resize(newuvsets.length()); |
---|
758 | // save vbas |
---|
759 | newvertices[vtxIdx].vba.resize(newweights[vtxIdx].length()); |
---|
760 | for (j=0; j<newweights[vtxIdx].length(); j++) |
---|
761 | { |
---|
762 | newvertices[vtxIdx].vba[j] = (newweights[vtxIdx])[j]; |
---|
763 | } |
---|
764 | // save joint ids |
---|
765 | newvertices[vtxIdx].jointIds.resize(newjointIds[vtxIdx].length()); |
---|
766 | for (j=0; j<newjointIds[vtxIdx].length(); j++) |
---|
767 | { |
---|
768 | newvertices[vtxIdx].jointIds[j] = (newjointIds[vtxIdx])[j]; |
---|
769 | } |
---|
770 | // save uv sets data |
---|
771 | for (j=0; j<newuvsets.length(); j++) |
---|
772 | { |
---|
773 | float2 uv; |
---|
774 | stat = faceIter.getUV(triVertexIdx[i],uv,&newuvsets[j]); |
---|
775 | if (MS::kSuccess != stat) |
---|
776 | { |
---|
777 | uv[0] = 0; |
---|
778 | uv[1] = 0; |
---|
779 | } |
---|
780 | newvertices[vtxIdx].u[j] = uv[0]; |
---|
781 | newvertices[vtxIdx].v[j] = (-1)*(uv[1]-1); |
---|
782 | } |
---|
783 | // save vertex index in face info |
---|
784 | newFace.v[i] = m_sharedGeom.vertices.size() + vtxIdx; |
---|
785 | // update value of index to next vertex info (-1 means nothing next) |
---|
786 | newvertices[vtxIdx].next = -1; |
---|
787 | } |
---|
788 | else // already found at least 1 vertex in this position |
---|
789 | { |
---|
790 | // check if a vertex with same attributes has been saved already |
---|
791 | for (k=vtxIdx; k!=-1 && different; k=newvertices[k].next) |
---|
792 | { |
---|
793 | different = false; |
---|
794 | |
---|
795 | if (params.exportVertNorm) |
---|
796 | { |
---|
797 | MFloatVector n1 = newnormals[newvertices[k].normalIdx]; |
---|
798 | MFloatVector n2 = newnormals[nrmIdx]; |
---|
799 | if (n1.x!=n2.x || n1.y!=n2.y || n1.z!=n2.z) |
---|
800 | { |
---|
801 | different = true; |
---|
802 | } |
---|
803 | } |
---|
804 | |
---|
805 | if ((params.exportVertCol) && |
---|
806 | (newvertices[k].r!=color.r || newvertices[k].g!=color.g || newvertices[k].b!= color.b || newvertices[k].a!=color.a)) |
---|
807 | { |
---|
808 | different = true; |
---|
809 | } |
---|
810 | |
---|
811 | if (params.exportTexCoord) |
---|
812 | { |
---|
813 | for (j=0; j<newuvsets.length(); j++) |
---|
814 | { |
---|
815 | float2 uv; |
---|
816 | stat = faceIter.getUV(triVertexIdx[i],uv,&newuvsets[j]); |
---|
817 | if (MS::kSuccess != stat) |
---|
818 | { |
---|
819 | uv[0] = 0; |
---|
820 | uv[1] = 0; |
---|
821 | } |
---|
822 | uv[1] = (-1)*(uv[1]-1); |
---|
823 | if (newvertices[k].u[j]!=uv[0] || newvertices[k].v[j]!=uv[1]) |
---|
824 | { |
---|
825 | different = true; |
---|
826 | } |
---|
827 | } |
---|
828 | } |
---|
829 | |
---|
830 | idx = k; |
---|
831 | } |
---|
832 | // if no identical vertex has been saved, then save the vertex info |
---|
833 | if (different) |
---|
834 | { |
---|
835 | vertexInfo vtx; |
---|
836 | // save vertex position |
---|
837 | vtx.pointIdx = vtxIdx; |
---|
838 | // save vertex normal |
---|
839 | vtx.normalIdx = nrmIdx; |
---|
840 | // save vertex colour |
---|
841 | vtx.r = color.r; |
---|
842 | vtx.g = color.g; |
---|
843 | vtx.b = color.b; |
---|
844 | vtx.a = color.a; |
---|
845 | // save vertex vba |
---|
846 | vtx.vba.resize(newweights[vtxIdx].length()); |
---|
847 | for (j=0; j<newweights[vtxIdx].length(); j++) |
---|
848 | { |
---|
849 | vtx.vba[j] = (newweights[vtxIdx])[j]; |
---|
850 | } |
---|
851 | // save joint ids |
---|
852 | vtx.jointIds.resize(newjointIds[vtxIdx].length()); |
---|
853 | for (j=0; j<newjointIds[vtxIdx].length(); j++) |
---|
854 | { |
---|
855 | vtx.jointIds[j] = (newjointIds[vtxIdx])[j]; |
---|
856 | } |
---|
857 | // save vertex texture coordinates |
---|
858 | vtx.u.resize(newuvsets.length()); |
---|
859 | vtx.v.resize(newuvsets.length()); |
---|
860 | for (j=0; j<newuvsets.length(); j++) |
---|
861 | { |
---|
862 | float2 uv; |
---|
863 | stat = faceIter.getUV(triVertexIdx[i],uv,&newuvsets[j]); |
---|
864 | if (MS::kSuccess != stat) |
---|
865 | { |
---|
866 | uv[0] = 0; |
---|
867 | uv[1] = 0; |
---|
868 | } |
---|
869 | if (fabs(uv[0]) < PRECISION) |
---|
870 | uv[0] = 0; |
---|
871 | if (fabs(uv[1]) < PRECISION) |
---|
872 | uv[1] = 0; |
---|
873 | vtx.u[j] = uv[0]; |
---|
874 | vtx.v[j] = (-1)*(uv[1]-1); |
---|
875 | } |
---|
876 | vtx.next = -1; |
---|
877 | newvertices.push_back(vtx); |
---|
878 | // save vertex index in face info |
---|
879 | newFace.v[i] = m_sharedGeom.vertices.size() + newvertices.size()-1; |
---|
880 | newvertices[idx].next = newvertices.size()-1; |
---|
881 | } |
---|
882 | else |
---|
883 | { |
---|
884 | newFace.v[i] = m_sharedGeom.vertices.size() + idx; |
---|
885 | } |
---|
886 | } |
---|
887 | } // end iteration of triangle vertices |
---|
888 | // add face info to the array corresponding to the submesh it belongs |
---|
889 | // skip faces with no shaders assigned |
---|
890 | if (shaderPolygonMapping[faceIter.index()] >= 0) |
---|
891 | polygonSets[shaderPolygonMapping[faceIter.index()]].push_back(newFace); |
---|
892 | } // end iteration of triangles |
---|
893 | } |
---|
894 | } |
---|
895 | std::cout << "done reading mesh triangles\n"; |
---|
896 | std::cout.flush(); |
---|
897 | return MS::kSuccess; |
---|
898 | } |
---|
899 | |
---|
900 | |
---|
901 | // Build shared geometry |
---|
902 | MStatus Mesh::buildSharedGeometry(const MDagPath &meshDag,ParamList& params) |
---|
903 | { |
---|
904 | int i,j,k; |
---|
905 | std::cout << "Create list of shared vertices\n"; |
---|
906 | std::cout.flush(); |
---|
907 | // save a new entry in the shared geometry map: we associate the index of the first |
---|
908 | // vertex we're loading with the dag path from which it has been read |
---|
909 | dagInfo di; |
---|
910 | di.offset = m_sharedGeom.vertices.size(); |
---|
911 | di.dagPath = meshDag; |
---|
912 | di.pBlendShape = pBlendShape; |
---|
913 | // load shared vertices |
---|
914 | for (i=0; i<newvertices.size(); i++) |
---|
915 | { |
---|
916 | vertex v; |
---|
917 | vertexInfo vInfo = newvertices[i]; |
---|
918 | // save vertex coordinates (rescale to desired length unit) |
---|
919 | MPoint point = newpoints[vInfo.pointIdx] * params.lum; |
---|
920 | if (fabs(point.x) < PRECISION) |
---|
921 | point.x = 0; |
---|
922 | if (fabs(point.y) < PRECISION) |
---|
923 | point.y = 0; |
---|
924 | if (fabs(point.z) < PRECISION) |
---|
925 | point.z = 0; |
---|
926 | v.x = point.x; |
---|
927 | v.y = point.y; |
---|
928 | v.z = point.z; |
---|
929 | // save vertex normal |
---|
930 | MFloatVector normal = newnormals[vInfo.normalIdx]; |
---|
931 | if (fabs(normal.x) < PRECISION) |
---|
932 | normal.x = 0; |
---|
933 | if (fabs(normal.y) < PRECISION) |
---|
934 | normal.y = 0; |
---|
935 | if (fabs(normal.z) < PRECISION) |
---|
936 | normal.z = 0; |
---|
937 | if (opposite) |
---|
938 | { |
---|
939 | v.n.x = -normal.x; |
---|
940 | v.n.y = -normal.y; |
---|
941 | v.n.z = -normal.z; |
---|
942 | } |
---|
943 | else |
---|
944 | { |
---|
945 | v.n.x = normal.x; |
---|
946 | v.n.y = normal.y; |
---|
947 | v.n.z = normal.z; |
---|
948 | } |
---|
949 | v.n.normalize(); |
---|
950 | // save vertex color |
---|
951 | v.r = vInfo.r; |
---|
952 | v.g = vInfo.g; |
---|
953 | v.b = vInfo.b; |
---|
954 | v.a = vInfo.a; |
---|
955 | // save vertex bone assignements |
---|
956 | for (k=0; k<vInfo.vba.size(); k++) |
---|
957 | { |
---|
958 | vba newVba; |
---|
959 | newVba.jointIdx = vInfo.jointIds[k]; |
---|
960 | newVba.weight = vInfo.vba[k]; |
---|
961 | v.vbas.push_back(newVba); |
---|
962 | } |
---|
963 | // save texture coordinates |
---|
964 | for (k=0; k<vInfo.u.size(); k++) |
---|
965 | { |
---|
966 | texcoords newTexCoords; |
---|
967 | newTexCoords.u = vInfo.u[k]; |
---|
968 | newTexCoords.v = vInfo.v[k]; |
---|
969 | newTexCoords.w = 0; |
---|
970 | v.texcoords.push_back(newTexCoords); |
---|
971 | } |
---|
972 | // save vertex index in maya mesh, to retrieve future positions of the same vertex |
---|
973 | v.index = vInfo.pointIdx; |
---|
974 | // add newly created vertex to vertices list |
---|
975 | m_sharedGeom.vertices.push_back(v); |
---|
976 | } |
---|
977 | // Make sure all vertices have the same number of texture coordinates |
---|
978 | for (i=0; i<m_sharedGeom.vertices.size(); i++) |
---|
979 | { |
---|
980 | vertex* pV = &m_sharedGeom.vertices[i]; |
---|
981 | for (j=pV->texcoords.size(); j<m_uvsets.size(); j++) |
---|
982 | { |
---|
983 | texcoords newTexCoords; |
---|
984 | newTexCoords.u = 0; |
---|
985 | newTexCoords.v = 0; |
---|
986 | newTexCoords.w = 0; |
---|
987 | pV->texcoords.push_back(newTexCoords); |
---|
988 | } |
---|
989 | } |
---|
990 | // save number of vertices referring to this mesh dag in the dag path map |
---|
991 | di.numVertices = m_sharedGeom.vertices.size() - di.offset; |
---|
992 | m_sharedGeom.dagMap.push_back(di); |
---|
993 | std::cout << "done creating vertices list\n"; |
---|
994 | std::cout.flush(); |
---|
995 | return MS::kSuccess; |
---|
996 | } |
---|
997 | |
---|
998 | |
---|
999 | // Create submeshes |
---|
1000 | MStatus Mesh::createSubmeshes(const MDagPath& meshDag,ParamList& params) |
---|
1001 | { |
---|
1002 | int i; |
---|
1003 | MStatus stat; |
---|
1004 | MFnMesh mesh(meshDag); |
---|
1005 | for (i=0; i<shaders.length(); i++) |
---|
1006 | { |
---|
1007 | // check if the submesh has at least 1 triangle |
---|
1008 | if (polygonSets[i].size() > 0) |
---|
1009 | { |
---|
1010 | //create new submesh |
---|
1011 | Submesh* pSubmesh = new Submesh(); |
---|
1012 | //load linked shader |
---|
1013 | stat = pSubmesh->loadMaterial(shaders[i],newuvsets,params); |
---|
1014 | if (stat != MS::kSuccess) |
---|
1015 | { |
---|
1016 | MFnDependencyNode shadingGroup(shaders[i]); |
---|
1017 | std::cout << "Error loading submesh linked to shader " << shadingGroup.name().asChar() << "\n"; |
---|
1018 | std::cout.flush(); |
---|
1019 | return MS::kFailure; |
---|
1020 | } |
---|
1021 | //load vertex and face data |
---|
1022 | stat = pSubmesh->load(meshDag,polygonSets[i],newvertices,newpoints,newnormals,newuvsets,params,opposite); |
---|
1023 | //if we're not using shared geometry, save a pointer to the blend shape deformer |
---|
1024 | if (pBlendShape && !params.useSharedGeom) |
---|
1025 | pSubmesh->m_pBlendShape = pBlendShape; |
---|
1026 | //add submesh to current mesh |
---|
1027 | m_submeshes.push_back(pSubmesh); |
---|
1028 | //update number of triangles composing the mesh |
---|
1029 | m_numTriangles += pSubmesh->numTriangles(); |
---|
1030 | } |
---|
1031 | } |
---|
1032 | return MS::kSuccess; |
---|
1033 | } |
---|
1034 | |
---|
1035 | |
---|
1036 | |
---|
1037 | |
---|
1038 | |
---|
1039 | /******************** Methods to read vertex animations from Maya ************************/ |
---|
1040 | //load a vertex animation clip |
---|
1041 | MStatus Mesh::loadClip(MString& clipName,float start,float stop,float rate,ParamList& params) |
---|
1042 | { |
---|
1043 | MStatus stat; |
---|
1044 | MString msg; |
---|
1045 | std::vector<float> times; |
---|
1046 | // calculate times from clip sample rate |
---|
1047 | times.clear(); |
---|
1048 | for (float t=start; t<stop; t+=rate) |
---|
1049 | times.push_back(t); |
---|
1050 | times.push_back(stop); |
---|
1051 | // get animation length |
---|
1052 | float length=0; |
---|
1053 | if (times.size() >= 0) |
---|
1054 | length = times[times.size()-1] - times[0]; |
---|
1055 | if (length < 0) |
---|
1056 | { |
---|
1057 | std::cout << "invalid time range for the clip, we skip it\n"; |
---|
1058 | std::cout.flush(); |
---|
1059 | return MS::kFailure; |
---|
1060 | } |
---|
1061 | // create a new animation |
---|
1062 | Animation a; |
---|
1063 | a.m_name = clipName; |
---|
1064 | a.m_length = length; |
---|
1065 | a.m_tracks.clear(); |
---|
1066 | // if we're using shared geometry, create a single animation track for the whole mesh |
---|
1067 | if (params.useSharedGeom) |
---|
1068 | { |
---|
1069 | // load the animation track |
---|
1070 | stat = loadMeshTrack(a,times,params); |
---|
1071 | if (stat != MS::kSuccess) |
---|
1072 | { |
---|
1073 | std::cout << "Error loading mesh vertex animation\n"; |
---|
1074 | std::cout.flush(); |
---|
1075 | } |
---|
1076 | } |
---|
1077 | // else creae a different animation track for each submesh |
---|
1078 | else |
---|
1079 | { |
---|
1080 | // load all tracks (one for each submesh) |
---|
1081 | stat = loadSubmeshTracks(a,times,params); |
---|
1082 | if (stat != MS::kSuccess) |
---|
1083 | { |
---|
1084 | std::cout << "Error loading submeshes vertex animation\n"; |
---|
1085 | std::cout.flush(); |
---|
1086 | return MS::kFailure; |
---|
1087 | } |
---|
1088 | } |
---|
1089 | // add newly created animation to animations list |
---|
1090 | m_vertexClips.push_back(a); |
---|
1091 | // display info |
---|
1092 | std::cout << "length: " << a.m_length << "\n"; |
---|
1093 | std::cout << "num keyframes: " << a.m_tracks[0].m_vertexKeyframes.size() << "\n"; |
---|
1094 | std::cout.flush(); |
---|
1095 | // clip successfully loaded |
---|
1096 | return MS::kSuccess; |
---|
1097 | } |
---|
1098 | |
---|
1099 | |
---|
1100 | //load an animation track for the whole mesh (using shared geometry) |
---|
1101 | MStatus Mesh::loadMeshTrack(Animation& a,std::vector<float> ×, OgreMayaExporter::ParamList ¶ms) |
---|
1102 | { |
---|
1103 | int i; |
---|
1104 | MStatus stat; |
---|
1105 | // create a new track |
---|
1106 | Track t; |
---|
1107 | t.m_type = TT_MORPH; |
---|
1108 | t.m_target = T_MESH; |
---|
1109 | t.m_vertexKeyframes.clear(); |
---|
1110 | // get keyframes at given times |
---|
1111 | for (i=0; i<times.size(); i++) |
---|
1112 | { |
---|
1113 | //set time to wanted sample time |
---|
1114 | MAnimControl::setCurrentTime(MTime(times[i],MTime::kSeconds)); |
---|
1115 | //load a keyframe for the mesh at current time |
---|
1116 | stat = loadKeyframe(t,times[i]-times[0],params); |
---|
1117 | if (stat != MS::kSuccess) |
---|
1118 | { |
---|
1119 | std::cout << "Error reading animation keyframe at time: " << times[i] << "\n"; |
---|
1120 | std::cout.flush(); |
---|
1121 | } |
---|
1122 | } |
---|
1123 | // add track to given animation |
---|
1124 | a.addTrack(t); |
---|
1125 | // track sucessfully loaded |
---|
1126 | return MS::kSuccess; |
---|
1127 | } |
---|
1128 | |
---|
1129 | |
---|
1130 | //load all submesh animation tracks (one for each submesh) |
---|
1131 | MStatus Mesh::loadSubmeshTracks(Animation& a,std::vector<float> ×, OgreMayaExporter::ParamList ¶ms) |
---|
1132 | { |
---|
1133 | int i,j; |
---|
1134 | MStatus stat; |
---|
1135 | // create a new track for each submesh |
---|
1136 | std::vector<Track> tracks; |
---|
1137 | for (i=0; i<m_submeshes.size(); i++) |
---|
1138 | { |
---|
1139 | Track t; |
---|
1140 | t.m_type = TT_MORPH; |
---|
1141 | t.m_target = T_SUBMESH; |
---|
1142 | t.m_index = i; |
---|
1143 | t.m_vertexKeyframes.clear(); |
---|
1144 | tracks.push_back(t); |
---|
1145 | } |
---|
1146 | // get keyframes at given times |
---|
1147 | for (i=0; i<times.size(); i++) |
---|
1148 | { |
---|
1149 | //set time to wanted sample time |
---|
1150 | MAnimControl::setCurrentTime(MTime(times[i],MTime::kSeconds)); |
---|
1151 | //load a keyframe for each submesh at current time |
---|
1152 | for (j=0; j<m_submeshes.size(); j++) |
---|
1153 | { |
---|
1154 | stat = m_submeshes[j]->loadKeyframe(tracks[j],times[i]-times[0],params); |
---|
1155 | if (stat != MS::kSuccess) |
---|
1156 | { |
---|
1157 | std::cout << "Error reading animation keyframe at time: " << times[i] << " for submesh: " << j << "\n"; |
---|
1158 | std::cout.flush(); |
---|
1159 | } |
---|
1160 | } |
---|
1161 | } |
---|
1162 | // add tracks to given animation |
---|
1163 | for (i=0; i< tracks.size(); i++) |
---|
1164 | a.addTrack(tracks[i]); |
---|
1165 | // track sucessfully loaded |
---|
1166 | return MS::kSuccess; |
---|
1167 | return MS::kSuccess; |
---|
1168 | } |
---|
1169 | |
---|
1170 | |
---|
1171 | // Load a keyframe for the whole mesh |
---|
1172 | MStatus Mesh::loadKeyframe(Track& t,float time,ParamList& params) |
---|
1173 | { |
---|
1174 | int i,j; |
---|
1175 | // create a new keyframe |
---|
1176 | vertexKeyframe k; |
---|
1177 | // set keyframe time |
---|
1178 | k.time = time; |
---|
1179 | for (i=0; i<m_sharedGeom.dagMap.size(); i++) |
---|
1180 | { |
---|
1181 | // get the mesh Fn |
---|
1182 | dagInfo di = m_sharedGeom.dagMap[i]; |
---|
1183 | MFnMesh mesh(di.dagPath); |
---|
1184 | // get vertex positions |
---|
1185 | MFloatPointArray points; |
---|
1186 | if (params.exportWorldCoords) |
---|
1187 | mesh.getPoints(points,MSpace::kWorld); |
---|
1188 | else |
---|
1189 | mesh.getPoints(points,MSpace::kObject); |
---|
1190 | // calculate vertex offsets |
---|
1191 | for (j=0; j<di.numVertices; j++) |
---|
1192 | { |
---|
1193 | vertexPosition pos; |
---|
1194 | vertex v = m_sharedGeom.vertices[di.offset+j]; |
---|
1195 | pos.x = points[v.index].x * params.lum; |
---|
1196 | pos.y = points[v.index].y * params.lum; |
---|
1197 | pos.z = points[v.index].z * params.lum; |
---|
1198 | if (fabs(pos.x) < PRECISION) |
---|
1199 | pos.x = 0; |
---|
1200 | if (fabs(pos.y) < PRECISION) |
---|
1201 | pos.y = 0; |
---|
1202 | if (fabs(pos.z) < PRECISION) |
---|
1203 | pos.z = 0; |
---|
1204 | k.positions.push_back(pos); |
---|
1205 | } |
---|
1206 | } |
---|
1207 | // add keyframe to given track |
---|
1208 | t.addVertexKeyframe(k); |
---|
1209 | // keyframe successfully loaded |
---|
1210 | return MS::kSuccess; |
---|
1211 | } |
---|
1212 | |
---|
1213 | /*********************************** Export mesh data **************************************/ |
---|
1214 | // Write to a OGRE binary mesh |
---|
1215 | MStatus Mesh::writeOgreBinary(ParamList ¶ms) |
---|
1216 | { |
---|
1217 | MStatus stat; |
---|
1218 | int i; |
---|
1219 | // If no mesh have been exported, skip mesh creation |
---|
1220 | if (m_submeshes.size() <= 0) |
---|
1221 | { |
---|
1222 | std::cout << "Warning: No meshes selected for export\n"; |
---|
1223 | std::cout.flush(); |
---|
1224 | return MS::kFailure; |
---|
1225 | } |
---|
1226 | // Construct mesh |
---|
1227 | Ogre::MeshPtr pMesh = Ogre::MeshManager::getSingleton().createManual(m_name.asChar(), |
---|
1228 | Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); |
---|
1229 | // Write shared geometry data |
---|
1230 | if (params.useSharedGeom) |
---|
1231 | { |
---|
1232 | createOgreSharedGeometry(pMesh,params); |
---|
1233 | } |
---|
1234 | // Write submeshes data |
---|
1235 | for (i=0; i<m_submeshes.size(); i++) |
---|
1236 | { |
---|
1237 | m_submeshes[i]->createOgreSubmesh(pMesh,params); |
---|
1238 | } |
---|
1239 | // Set skeleton link (if present) |
---|
1240 | if (m_pSkeleton && params.exportSkeleton) |
---|
1241 | { |
---|
1242 | int ri = params.skeletonFilename.rindex('\\'); |
---|
1243 | int end = params.skeletonFilename.length() - 1; |
---|
1244 | MString filename = params.skeletonFilename.substring(ri+1,end); |
---|
1245 | pMesh->setSkeletonName(filename.asChar()); |
---|
1246 | } |
---|
1247 | // Write poses |
---|
1248 | if (params.exportBlendShapes) |
---|
1249 | { |
---|
1250 | createOgrePoses(pMesh,params); |
---|
1251 | } |
---|
1252 | // Write vertex animations |
---|
1253 | if (params.exportVertAnims) |
---|
1254 | { |
---|
1255 | createOgreVertexAnimations(pMesh,params); |
---|
1256 | } |
---|
1257 | // Write pose animations |
---|
1258 | if (params.exportBSAnims) |
---|
1259 | { |
---|
1260 | createOgrePoseAnimations(pMesh,params); |
---|
1261 | } |
---|
1262 | // Create a bounding box for the mesh |
---|
1263 | Ogre::AxisAlignedBox bbox = pMesh->getBounds(); |
---|
1264 | for(i=0; i<m_submeshes.size(); i++) |
---|
1265 | { |
---|
1266 | MPoint min1 = m_submeshes[i]->m_boundingBox.min(); |
---|
1267 | MPoint max1 = m_submeshes[i]->m_boundingBox.max(); |
---|
1268 | Ogre::Vector3 min2(min1.x,min1.y,min1.z); |
---|
1269 | Ogre::Vector3 max2(max1.x,max1.y,max1.z); |
---|
1270 | Ogre::AxisAlignedBox newbbox; |
---|
1271 | newbbox.setExtents(min2,max2); |
---|
1272 | bbox.merge(newbbox); |
---|
1273 | } |
---|
1274 | // Define mesh bounds |
---|
1275 | pMesh->_setBounds(bbox,false); |
---|
1276 | // Build edges list |
---|
1277 | if (params.buildEdges) |
---|
1278 | { |
---|
1279 | pMesh->buildEdgeList(); |
---|
1280 | } |
---|
1281 | // Build tangents |
---|
1282 | if (params.buildTangents) |
---|
1283 | { |
---|
1284 | bool canBuild = true; |
---|
1285 | unsigned short srcTex, destTex; |
---|
1286 | try { |
---|
1287 | pMesh->suggestTangentVectorBuildParams(srcTex, destTex); |
---|
1288 | } catch(Ogre::Exception e) { |
---|
1289 | canBuild = false; |
---|
1290 | } |
---|
1291 | if (canBuild) |
---|
1292 | pMesh->buildTangentVectors(srcTex, destTex); |
---|
1293 | } |
---|
1294 | // Export the binary mesh |
---|
1295 | Ogre::MeshSerializer serializer; |
---|
1296 | serializer.exportMesh(pMesh.getPointer(),params.meshFilename.asChar()); |
---|
1297 | pMesh.setNull(); |
---|
1298 | return MS::kSuccess; |
---|
1299 | } |
---|
1300 | |
---|
1301 | // Create shared geometry data for an Ogre mesh |
---|
1302 | MStatus Mesh::createOgreSharedGeometry(Ogre::MeshPtr pMesh,ParamList& params) |
---|
1303 | { |
---|
1304 | int i,j; |
---|
1305 | MStatus stat; |
---|
1306 | pMesh->sharedVertexData = new Ogre::VertexData(); |
---|
1307 | pMesh->sharedVertexData->vertexCount = m_sharedGeom.vertices.size(); |
---|
1308 | // Define a new vertex declaration |
---|
1309 | Ogre::VertexDeclaration* pDecl = new Ogre::VertexDeclaration(); |
---|
1310 | pMesh->sharedVertexData->vertexDeclaration = pDecl; |
---|
1311 | unsigned buf = 0; |
---|
1312 | size_t offset = 0; |
---|
1313 | // Add vertex position |
---|
1314 | pDecl->addElement(buf,offset,Ogre::VET_FLOAT3,Ogre::VES_POSITION); |
---|
1315 | offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); |
---|
1316 | // Add vertex normal |
---|
1317 | if (params.exportVertNorm) |
---|
1318 | { |
---|
1319 | pDecl->addElement(buf, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); |
---|
1320 | offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); |
---|
1321 | } |
---|
1322 | // Add vertex colour |
---|
1323 | if (params.exportVertCol) |
---|
1324 | { |
---|
1325 | pDecl->addElement(buf, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE); |
---|
1326 | offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT4); |
---|
1327 | } |
---|
1328 | // Add texture coordinates |
---|
1329 | for (i=0; i<m_sharedGeom.vertices[0].texcoords.size(); i++) |
---|
1330 | { |
---|
1331 | Ogre::VertexElementType uvType = Ogre::VertexElement::multiplyTypeCount(Ogre::VET_FLOAT1, 2); |
---|
1332 | pDecl->addElement(buf, offset, uvType, Ogre::VES_TEXTURE_COORDINATES, i); |
---|
1333 | offset += Ogre::VertexElement::getTypeSize(uvType); |
---|
1334 | } |
---|
1335 | // Get optimal vertex declaration |
---|
1336 | Ogre::VertexDeclaration* pOptimalDecl = pDecl->getAutoOrganisedDeclaration(params.exportVBA,params.exportBlendShapes || params.exportVertAnims); |
---|
1337 | // Create the vertex buffer using the newly created vertex declaration |
---|
1338 | stat = createOgreVertexBuffer(pMesh,pDecl,m_sharedGeom.vertices); |
---|
1339 | // Write vertex bone assignements list |
---|
1340 | if (params.exportVBA) |
---|
1341 | { |
---|
1342 | // Create a new vertex bone assignements list |
---|
1343 | Ogre::Mesh::VertexBoneAssignmentList vbas; |
---|
1344 | // Scan list of shared geometry vertices |
---|
1345 | for (i=0; i<m_sharedGeom.vertices.size(); i++) |
---|
1346 | { |
---|
1347 | vertex v = m_sharedGeom.vertices[i]; |
---|
1348 | // Add all bone assignements for every vertex to the bone assignements list |
---|
1349 | for (j=0; j<v.vbas.size(); j++) |
---|
1350 | { |
---|
1351 | Ogre::VertexBoneAssignment vba; |
---|
1352 | vba.vertexIndex = i; |
---|
1353 | vba.boneIndex = v.vbas[j].jointIdx; |
---|
1354 | vba.weight = v.vbas[j].weight; |
---|
1355 | if (vba.weight > 0.0f) |
---|
1356 | vbas.insert(Ogre::Mesh::VertexBoneAssignmentList::value_type(i, vba)); |
---|
1357 | } |
---|
1358 | } |
---|
1359 | // Rationalise the bone assignements list |
---|
1360 | pMesh->_rationaliseBoneAssignments(pMesh->sharedVertexData->vertexCount,vbas); |
---|
1361 | // Add bone assignements to the mesh |
---|
1362 | for (Ogre::Mesh::VertexBoneAssignmentList::iterator bi = vbas.begin(); bi != vbas.end(); bi++) |
---|
1363 | { |
---|
1364 | pMesh->addBoneAssignment(bi->second); |
---|
1365 | } |
---|
1366 | pMesh->_compileBoneAssignments(); |
---|
1367 | pMesh->_updateCompiledBoneAssignments(); |
---|
1368 | } |
---|
1369 | // Reorganize vertex buffers |
---|
1370 | pMesh->sharedVertexData->reorganiseBuffers(pOptimalDecl); |
---|
1371 | |
---|
1372 | return MS::kSuccess; |
---|
1373 | } |
---|
1374 | |
---|
1375 | // Create an Ogre compatible vertex buffer |
---|
1376 | MStatus Mesh::createOgreVertexBuffer(Ogre::MeshPtr pMesh,Ogre::VertexDeclaration* pDecl,const std::vector<vertex>& vertices) |
---|
1377 | { |
---|
1378 | Ogre::HardwareVertexBufferSharedPtr vbuf = |
---|
1379 | Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(pDecl->getVertexSize(0), |
---|
1380 | pMesh->sharedVertexData->vertexCount, |
---|
1381 | Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); |
---|
1382 | pMesh->sharedVertexData->vertexBufferBinding->setBinding(0, vbuf); |
---|
1383 | size_t vertexSize = pDecl->getVertexSize(0); |
---|
1384 | char* pBase = static_cast<char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD)); |
---|
1385 | Ogre::VertexDeclaration::VertexElementList elems = pDecl->findElementsBySource(0); |
---|
1386 | Ogre::VertexDeclaration::VertexElementList::iterator ei, eiend; |
---|
1387 | eiend = elems.end(); |
---|
1388 | float* pFloat; |
---|
1389 | // Fill the vertex buffer with shared geometry data |
---|
1390 | long vi; |
---|
1391 | Ogre::ColourValue col; |
---|
1392 | float ucoord, vcoord; |
---|
1393 | for (vi=0; vi<vertices.size(); vi++) |
---|
1394 | { |
---|
1395 | int iTexCoord = 0; |
---|
1396 | vertex v = vertices[vi]; |
---|
1397 | for (ei = elems.begin(); ei != eiend; ++ei) |
---|
1398 | { |
---|
1399 | Ogre::VertexElement& elem = *ei; |
---|
1400 | switch(elem.getSemantic()) |
---|
1401 | { |
---|
1402 | case Ogre::VES_POSITION: |
---|
1403 | elem.baseVertexPointerToElement(pBase, &pFloat); |
---|
1404 | *pFloat++ = v.x; |
---|
1405 | *pFloat++ = v.y; |
---|
1406 | *pFloat++ = v.z; |
---|
1407 | break; |
---|
1408 | case Ogre::VES_NORMAL: |
---|
1409 | elem.baseVertexPointerToElement(pBase, &pFloat); |
---|
1410 | *pFloat++ = v.n.x; |
---|
1411 | *pFloat++ = v.n.y; |
---|
1412 | *pFloat++ = v.n.z; |
---|
1413 | break; |
---|
1414 | case Ogre::VES_DIFFUSE: |
---|
1415 | elem.baseVertexPointerToElement(pBase, &pFloat); |
---|
1416 | *pFloat++ = v.r; |
---|
1417 | *pFloat++ = v.g; |
---|
1418 | *pFloat++ = v.b; |
---|
1419 | *pFloat++ = v.a; |
---|
1420 | break; |
---|
1421 | case Ogre::VES_TEXTURE_COORDINATES: |
---|
1422 | elem.baseVertexPointerToElement(pBase, &pFloat); |
---|
1423 | ucoord = v.texcoords[iTexCoord].u; |
---|
1424 | vcoord = v.texcoords[iTexCoord].v; |
---|
1425 | *pFloat++ = ucoord; |
---|
1426 | *pFloat++ = vcoord; |
---|
1427 | iTexCoord++; |
---|
1428 | break; |
---|
1429 | } |
---|
1430 | } |
---|
1431 | pBase += vertexSize; |
---|
1432 | } |
---|
1433 | vbuf->unlock(); |
---|
1434 | return MS::kSuccess; |
---|
1435 | } |
---|
1436 | // Create mesh poses for an Ogre mesh |
---|
1437 | MStatus Mesh::createOgrePoses(Ogre::MeshPtr pMesh,ParamList& params) |
---|
1438 | { |
---|
1439 | int i,j,k; |
---|
1440 | if (params.useSharedGeom) |
---|
1441 | { |
---|
1442 | // Read poses associated from all blendshapes associated to the shared geometry |
---|
1443 | for (i=0; i<m_sharedGeom.dagMap.size(); i++) |
---|
1444 | { |
---|
1445 | BlendShape* pBS = m_sharedGeom.dagMap[i].pBlendShape; |
---|
1446 | // Check if we have a blend shape associated to this subset of the shared geometry |
---|
1447 | if (pBS) |
---|
1448 | { |
---|
1449 | // Get all poses from current blend shape deformer |
---|
1450 | for (j=0; j<pBS->getPoses().size(); j++) |
---|
1451 | { |
---|
1452 | // Get the pose |
---|
1453 | pose* p = &(pBS->getPoses()[j]); |
---|
1454 | if (p->name == "") |
---|
1455 | { |
---|
1456 | p->name = "pose"; |
---|
1457 | p->name += j; |
---|
1458 | } |
---|
1459 | // Create a new pose for the ogre mesh |
---|
1460 | Ogre::Pose* pPose = pMesh->createPose(0,p->name.asChar()); |
---|
1461 | // Set the pose attributes |
---|
1462 | for (k=0; k<p->offsets.size(); k++) |
---|
1463 | { |
---|
1464 | Ogre::Vector3 offset(p->offsets[k].x,p->offsets[k].y,p->offsets[k].z); |
---|
1465 | pPose->addVertex(p->offsets[k].index,offset); |
---|
1466 | } |
---|
1467 | } |
---|
1468 | } |
---|
1469 | } |
---|
1470 | } |
---|
1471 | else |
---|
1472 | { |
---|
1473 | // Get poses associated to the submeshes |
---|
1474 | for (i=0; i<m_submeshes.size(); i++) |
---|
1475 | { |
---|
1476 | BlendShape* pBS = m_submeshes[i]->m_pBlendShape; |
---|
1477 | // Check if this submesh has a blend shape deformer associated |
---|
1478 | if (pBS) |
---|
1479 | { |
---|
1480 | // Get all poses from current blend shape deformer |
---|
1481 | for (j=0; j<pBS->getPoses().size(); j++) |
---|
1482 | { |
---|
1483 | // Get the pose |
---|
1484 | pose* p = &(pBS->getPoses()[j]); |
---|
1485 | if (p->name == "") |
---|
1486 | { |
---|
1487 | p->name = "pose"; |
---|
1488 | p->name += j; |
---|
1489 | } |
---|
1490 | // Create a new pose for the ogre mesh |
---|
1491 | Ogre::Pose* pPose = pMesh->createPose(p->index,p->name.asChar()); |
---|
1492 | // Set the pose attributes |
---|
1493 | for (k=0; k<p->offsets.size(); k++) |
---|
1494 | { |
---|
1495 | Ogre::Vector3 offset(p->offsets[k].x,p->offsets[k].y,p->offsets[k].z); |
---|
1496 | pPose->addVertex(p->offsets[k].index,offset); |
---|
1497 | } |
---|
1498 | } |
---|
1499 | } |
---|
1500 | } |
---|
1501 | } |
---|
1502 | return MS::kSuccess; |
---|
1503 | } |
---|
1504 | // Create vertex animations for an Ogre mesh |
---|
1505 | MStatus Mesh::createOgreVertexAnimations(Ogre::MeshPtr pMesh,ParamList& params) |
---|
1506 | { |
---|
1507 | int i,j,k; |
---|
1508 | std::cout << "pippo\n"; |
---|
1509 | std::cout.flush(); |
---|
1510 | // Read the list of vertex animation clips |
---|
1511 | for (i=0; i<m_vertexClips.size(); i++) |
---|
1512 | { |
---|
1513 | // Create a new animation |
---|
1514 | Ogre::Animation* pAnimation = pMesh->createAnimation(m_vertexClips[i].m_name.asChar(),m_vertexClips[i].m_length); |
---|
1515 | // Create all tracks for current animation |
---|
1516 | for (j=0; j<m_vertexClips[i].m_tracks.size(); j++) |
---|
1517 | { |
---|
1518 | Track* t = &(m_vertexClips[i].m_tracks[j]); |
---|
1519 | // Create a new track |
---|
1520 | Ogre::VertexAnimationTrack* pTrack; |
---|
1521 | if (t->m_target == T_MESH) |
---|
1522 | pTrack = pAnimation->createVertexTrack(0,pMesh->sharedVertexData,Ogre::VAT_MORPH); |
---|
1523 | else |
---|
1524 | { |
---|
1525 | pTrack = pAnimation->createVertexTrack(t->m_index+1,pMesh->getSubMesh(t->m_index)->vertexData, |
---|
1526 | Ogre::VAT_MORPH); |
---|
1527 | } |
---|
1528 | // Create keyframes for current track |
---|
1529 | for (k=0; k<t->m_vertexKeyframes.size(); k++) |
---|
1530 | { |
---|
1531 | // Create a new keyframe |
---|
1532 | Ogre::VertexMorphKeyFrame* pKeyframe = pTrack->createVertexMorphKeyFrame(t->m_vertexKeyframes[k].time); |
---|
1533 | // Create vertex buffer for current keyframe |
---|
1534 | Ogre::HardwareVertexBufferSharedPtr pBuffer = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer( |
---|
1535 | Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), |
---|
1536 | t->m_vertexKeyframes[k].positions.size(), |
---|
1537 | Ogre::HardwareBuffer::HBU_STATIC, true); |
---|
1538 | float* pFloat = static_cast<float*>(pBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD)); |
---|
1539 | // Fill the vertex buffer with vertex positions |
---|
1540 | int vi; |
---|
1541 | std::vector<vertexPosition>& positions = t->m_vertexKeyframes[k].positions; |
---|
1542 | for (vi=0; vi<positions.size(); vi++) |
---|
1543 | { |
---|
1544 | *pFloat++ = static_cast<float>(positions[vi].x); |
---|
1545 | *pFloat++ = static_cast<float>(positions[vi].y); |
---|
1546 | *pFloat++ = static_cast<float>(positions[vi].z); |
---|
1547 | } |
---|
1548 | // Unlock vertex buffer |
---|
1549 | pBuffer->unlock(); |
---|
1550 | // Set vertex buffer for current keyframe |
---|
1551 | pKeyframe->setVertexBuffer(pBuffer); |
---|
1552 | } |
---|
1553 | } |
---|
1554 | } |
---|
1555 | return MS::kSuccess; |
---|
1556 | } |
---|
1557 | // Create pose animations for an Ogre mesh |
---|
1558 | MStatus Mesh::createOgrePoseAnimations(Ogre::MeshPtr pMesh,ParamList& params) |
---|
1559 | { |
---|
1560 | int i,j,k; |
---|
1561 | // Get all loaded blend shape clips |
---|
1562 | for (i=0; i<m_BSClips.size(); i++) |
---|
1563 | { |
---|
1564 | // Create a new animation for each clip |
---|
1565 | Ogre::Animation* pAnimation = pMesh->createAnimation(m_BSClips[i].m_name.asChar(),m_BSClips[i].m_length); |
---|
1566 | // Create animation tracks for this animation |
---|
1567 | for (j=0; j<m_BSClips[i].m_tracks.size(); j++) |
---|
1568 | { |
---|
1569 | Track* t = &m_BSClips[i].m_tracks[j]; |
---|
1570 | // Create a new track |
---|
1571 | Ogre::VertexAnimationTrack* pTrack; |
---|
1572 | if (t->m_target == T_MESH) |
---|
1573 | pTrack = pAnimation->createVertexTrack(0,pMesh->sharedVertexData,Ogre::VAT_POSE); |
---|
1574 | else |
---|
1575 | { |
---|
1576 | pTrack = pAnimation->createVertexTrack(t->m_index+1,pMesh->getSubMesh(t->m_index)->vertexData, |
---|
1577 | Ogre::VAT_POSE); |
---|
1578 | } |
---|
1579 | // Create keyframes for current track |
---|
1580 | for (k=0; k<t->m_vertexKeyframes.size(); k++) |
---|
1581 | { |
---|
1582 | Ogre::VertexPoseKeyFrame* pKeyframe = pTrack->createVertexPoseKeyFrame(t->m_vertexKeyframes[k].time); |
---|
1583 | int pri; |
---|
1584 | for (pri=0; pri<t->m_vertexKeyframes[k].poserefs.size(); pri++) |
---|
1585 | { |
---|
1586 | vertexPoseRef* pr = &t->m_vertexKeyframes[k].poserefs[pri]; |
---|
1587 | pKeyframe->addPoseReference(pr->poseIndex,pr->poseWeight); |
---|
1588 | } |
---|
1589 | } |
---|
1590 | } |
---|
1591 | } |
---|
1592 | return MS::kSuccess; |
---|
1593 | } |
---|
1594 | |
---|
1595 | }; //end of namespace |
---|