Panda3D
|
00001 // Filename: mayaNodeDesc.cxx 00002 // Created by: drose (06Jun03) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "mayaNodeDesc.h" 00016 #include "mayaNodeTree.h" 00017 #include "mayaBlendDesc.h" 00018 #include "mayaToEggConverter.h" 00019 #include "maya_funcs.h" 00020 #include "eggGroup.h" 00021 #include "config_mayaegg.h" 00022 00023 #include "pre_maya_include.h" 00024 #include <maya/MFnBlendShapeDeformer.h> 00025 #include <maya/MItDependencyGraph.h> 00026 #include <maya/MFnNurbsSurface.h> 00027 #include <maya/MFnMesh.h> 00028 #include "post_maya_include.h" 00029 00030 TypeHandle MayaNodeDesc::_type_handle; 00031 00032 // This is a list of the names of Maya connections that count as a 00033 // transform. 00034 static const char *transform_connections[] = { 00035 "translate", 00036 "translateX", 00037 "translateY", 00038 "translateZ", 00039 "rotate", 00040 "rotateX", 00041 "rotateY", 00042 "rotateZ", 00043 }; 00044 static const int num_transform_connections = sizeof(transform_connections) / sizeof(const char *); 00045 00046 //////////////////////////////////////////////////////////////////// 00047 // Function: MayaNodeDesc::Constructor 00048 // Access: Public 00049 // Description: 00050 //////////////////////////////////////////////////////////////////// 00051 MayaNodeDesc:: 00052 MayaNodeDesc(MayaNodeTree *tree, MayaNodeDesc *parent, const string &name) : 00053 Namable(name), 00054 _tree(tree), 00055 _parent(parent) 00056 { 00057 _dag_path = (MDagPath *)NULL; 00058 _egg_group = (EggGroup *)NULL; 00059 _egg_table = (EggTable *)NULL; 00060 _anim = (EggXfmSAnim *)NULL; 00061 _joint_type = JT_none; 00062 _is_lod = false; 00063 _tagged = false; 00064 _joint_tagged = false; 00065 00066 // Add ourselves to our parent. 00067 if (_parent != (MayaNodeDesc *)NULL) { 00068 _parent->_children.push_back(this); 00069 } 00070 } 00071 00072 //////////////////////////////////////////////////////////////////// 00073 // Function: MayaNodeDesc::Destructor 00074 // Access: Public 00075 // Description: 00076 //////////////////////////////////////////////////////////////////// 00077 MayaNodeDesc:: 00078 ~MayaNodeDesc() { 00079 if (_dag_path != (MDagPath *)NULL) { 00080 delete _dag_path; 00081 } 00082 } 00083 00084 //////////////////////////////////////////////////////////////////// 00085 // Function: MayaNodeDesc::from_dag_path 00086 // Access: Public 00087 // Description: Indicates an association between the MayaNodeDesc and 00088 // some Maya instance. 00089 //////////////////////////////////////////////////////////////////// 00090 void MayaNodeDesc:: 00091 from_dag_path(const MDagPath &dag_path, MayaToEggConverter *converter) { 00092 MStatus status; 00093 00094 if (_dag_path == (MDagPath *)NULL) { 00095 _dag_path = new MDagPath(dag_path); 00096 00097 string name; 00098 MFnDagNode dag_node(dag_path, &status); 00099 if (!status) { 00100 status.perror("MFnDagNode constructor"); 00101 } else { 00102 name = dag_node.name().asChar(); 00103 } 00104 00105 if (_dag_path->hasFn(MFn::kJoint) || converter->force_joint(name)) { 00106 // This node is a joint, or the user specifically asked to treat 00107 // it like a joint. 00108 _joint_type = JT_joint; 00109 if (_parent != (MayaNodeDesc *)NULL) { 00110 _parent->mark_joint_parent(); 00111 } 00112 00113 } else { 00114 // The node is not a joint, but maybe its transform is 00115 // controlled by connected inputs. If so, we should treat it 00116 // like a joint. 00117 bool transform_connected = false; 00118 00119 MStatus status; 00120 MObject node = dag_path.node(&status); 00121 if (status) { 00122 for (int i = 0; 00123 i < num_transform_connections && !transform_connected; 00124 i++) { 00125 if (is_connected(node, transform_connections[i])) { 00126 transform_connected = true; 00127 } 00128 } 00129 } 00130 00131 if (transform_connected) { 00132 _joint_type = JT_joint; 00133 if (_parent != (MayaNodeDesc *)NULL) { 00134 _parent->mark_joint_parent(); 00135 } 00136 } 00137 } 00138 00139 if (dag_path.hasFn(MFn::kNurbsSurface)) { 00140 MFnNurbsSurface surface(dag_path, &status); 00141 if (status) { 00142 check_blend_shapes(surface, "create"); 00143 } 00144 } else if (dag_path.hasFn(MFn::kMesh)) { 00145 MFnMesh mesh(dag_path, &status); 00146 if (status) { 00147 check_blend_shapes(mesh, "inMesh"); 00148 } 00149 } 00150 } 00151 } 00152 00153 //////////////////////////////////////////////////////////////////// 00154 // Function: MayaNodeDesc::has_dag_path 00155 // Access: Public 00156 // Description: Returns true if a Maya dag path has been associated 00157 // with this node, false otherwise. 00158 //////////////////////////////////////////////////////////////////// 00159 bool MayaNodeDesc:: 00160 has_dag_path() const { 00161 return (_dag_path != (MDagPath *)NULL); 00162 } 00163 00164 //////////////////////////////////////////////////////////////////// 00165 // Function: MayaNodeDesc::get_dag_path 00166 // Access: Public 00167 // Description: Returns the dag path associated with this node. It 00168 // is an error to call this unless has_dag_path() 00169 // returned true. 00170 //////////////////////////////////////////////////////////////////// 00171 const MDagPath &MayaNodeDesc:: 00172 get_dag_path() const { 00173 nassertr(_dag_path != (MDagPath *)NULL, *_dag_path); 00174 return *_dag_path; 00175 } 00176 00177 //////////////////////////////////////////////////////////////////// 00178 // Function: MayaNodeDesc::get_num_blend_descs 00179 // Access: Public 00180 // Description: Returns the number of unique MayaBlendDesc objects 00181 // (and hence the number of morph sliders) that affect 00182 // the geometry in this node. 00183 //////////////////////////////////////////////////////////////////// 00184 int MayaNodeDesc:: 00185 get_num_blend_descs() const { 00186 return _blend_descs.size(); 00187 } 00188 00189 //////////////////////////////////////////////////////////////////// 00190 // Function: MayaNodeDesc::get_blend_desc 00191 // Access: Public 00192 // Description: Returns the nth MayaBlendDesc object that affects the 00193 // geometry in this node. 00194 //////////////////////////////////////////////////////////////////// 00195 MayaBlendDesc *MayaNodeDesc:: 00196 get_blend_desc(int n) const { 00197 nassertr(n >= 0 && n < (int)_blend_descs.size(), NULL); 00198 return _blend_descs[n]; 00199 } 00200 00201 //////////////////////////////////////////////////////////////////// 00202 // Function: MayaNodeDesc::is_joint 00203 // Access: Public 00204 // Description: Returns true if the node should be treated as a joint 00205 // by the converter. 00206 //////////////////////////////////////////////////////////////////// 00207 bool MayaNodeDesc:: 00208 is_joint() const { 00209 //return _joint_type == JT_joint || _joint_type == JT_pseudo_joint; 00210 return _joint_tagged && (_joint_type == JT_joint || _joint_type == JT_pseudo_joint); 00211 } 00212 00213 //////////////////////////////////////////////////////////////////// 00214 // Function: MayaNodeDesc::is_joint_parent 00215 // Access: Public 00216 // Description: Returns true if the node is the parent or ancestor of 00217 // a joint. 00218 //////////////////////////////////////////////////////////////////// 00219 bool MayaNodeDesc:: 00220 is_joint_parent() const { 00221 return _joint_type == JT_joint_parent; 00222 //return _joint_tagged && (_joint_type == JT_joint_parent); 00223 } 00224 00225 //////////////////////////////////////////////////////////////////// 00226 // Function: MayaNodeDesc::is_joint_tagged 00227 // Access: Public 00228 // Description: Returns true if the node has been joint_tagged to be 00229 // converted, false otherwise. 00230 //////////////////////////////////////////////////////////////////// 00231 bool MayaNodeDesc:: 00232 is_joint_tagged() const { 00233 return _joint_tagged; 00234 } 00235 00236 //////////////////////////////////////////////////////////////////// 00237 // Function: MayaNodeDesc::tag_joint 00238 // Access: Private 00239 // Description: Tags this node for conversion, but does not tag child 00240 // nodes. 00241 //////////////////////////////////////////////////////////////////// 00242 void MayaNodeDesc:: 00243 tag_joint() { 00244 _joint_tagged = true; 00245 } 00246 00247 //////////////////////////////////////////////////////////////////// 00248 // Function: MayaNodeDesc::tag_joint_recursively 00249 // Access: Private 00250 // Description: Tags this node and all descendant nodes for 00251 // conversion. 00252 //////////////////////////////////////////////////////////////////// 00253 void MayaNodeDesc:: 00254 tag_joint_recursively() { 00255 _joint_tagged = true; 00256 //mayaegg_cat.info() << "tjr: " << get_name() << endl; 00257 Children::const_iterator ci; 00258 for (ci = _children.begin(); ci != _children.end(); ++ci) { 00259 MayaNodeDesc *child = (*ci); 00260 child->tag_joint_recursively(); 00261 } 00262 } 00263 00264 //////////////////////////////////////////////////////////////////// 00265 // Function: MayaNodeDesc::is_tagged 00266 // Access: Public 00267 // Description: Returns true if the node has been tagged to be 00268 // converted, false otherwise. 00269 //////////////////////////////////////////////////////////////////// 00270 bool MayaNodeDesc:: 00271 is_tagged() const { 00272 return _tagged; 00273 } 00274 00275 //////////////////////////////////////////////////////////////////// 00276 // Function: MayaNodeDesc::tag 00277 // Access: Private 00278 // Description: Tags this node for conversion, but does not tag child 00279 // nodes. 00280 //////////////////////////////////////////////////////////////////// 00281 void MayaNodeDesc:: 00282 tag() { 00283 _tagged = true; 00284 } 00285 00286 //////////////////////////////////////////////////////////////////// 00287 // Function: MayaNodeDesc::untag 00288 // Access: Private 00289 // Description: Un-tags this node for conversion, but does not tag child 00290 // nodes. 00291 //////////////////////////////////////////////////////////////////// 00292 void MayaNodeDesc:: 00293 untag() { 00294 _tagged = false; 00295 } 00296 00297 //////////////////////////////////////////////////////////////////// 00298 // Function: MayaNodeDesc::tag_recursively 00299 // Access: Private 00300 // Description: Tags this node and all descendant nodes for 00301 // conversion. 00302 //////////////////////////////////////////////////////////////////// 00303 void MayaNodeDesc:: 00304 tag_recursively() { 00305 _tagged = true; 00306 00307 Children::const_iterator ci; 00308 for (ci = _children.begin(); ci != _children.end(); ++ci) { 00309 MayaNodeDesc *child = (*ci); 00310 child->tag_recursively(); 00311 } 00312 } 00313 00314 //////////////////////////////////////////////////////////////////// 00315 // Function: MayaNodeDesc::untag_recursively 00316 // Access: Private 00317 // Description: Un-tags this node and all descendant nodes for 00318 // conversion. 00319 //////////////////////////////////////////////////////////////////// 00320 void MayaNodeDesc:: 00321 untag_recursively() { 00322 _tagged = false; 00323 00324 Children::const_iterator ci; 00325 for (ci = _children.begin(); ci != _children.end(); ++ci) { 00326 MayaNodeDesc *child = (*ci); 00327 child->untag_recursively(); 00328 } 00329 } 00330 00331 //////////////////////////////////////////////////////////////////// 00332 // Function: MayaNodeDesc::has_object_type 00333 // Access: Public 00334 // Description: Returns true if this node or any of its parent 00335 // has_object_type of object_type. 00336 //////////////////////////////////////////////////////////////////// 00337 bool MayaNodeDesc:: 00338 has_object_type(string object_type) const { 00339 bool ret = false; 00340 if ((_egg_group != (EggGroup*) NULL) 00341 && _egg_group->has_object_type(object_type)) { 00342 return true; 00343 } 00344 if (_parent != (MayaNodeDesc *)NULL) { 00345 ret |= _parent->has_object_type(object_type); 00346 } 00347 return ret; 00348 } 00349 00350 //////////////////////////////////////////////////////////////////// 00351 // Function: MayaNodeDesc::clear_egg 00352 // Access: Private 00353 // Description: Recursively clears the egg pointers from this node 00354 // and all children. 00355 //////////////////////////////////////////////////////////////////// 00356 void MayaNodeDesc:: 00357 clear_egg() { 00358 _egg_group = (EggGroup *)NULL; 00359 _egg_table = (EggTable *)NULL; 00360 _anim = (EggXfmSAnim *)NULL; 00361 00362 Children::const_iterator ci; 00363 for (ci = _children.begin(); ci != _children.end(); ++ci) { 00364 MayaNodeDesc *child = (*ci); 00365 child->clear_egg(); 00366 } 00367 } 00368 00369 //////////////////////////////////////////////////////////////////// 00370 // Function: MayaNodeDesc::mark_joint_parent 00371 // Access: Private 00372 // Description: Indicates that this node has at least one child that 00373 // is a joint or a pseudo-joint. 00374 //////////////////////////////////////////////////////////////////// 00375 void MayaNodeDesc:: 00376 mark_joint_parent() { 00377 if (_joint_type == JT_none) { 00378 _joint_type = JT_joint_parent; 00379 if (_parent != (MayaNodeDesc *)NULL) { 00380 _parent->mark_joint_parent(); 00381 } 00382 } 00383 } 00384 00385 //////////////////////////////////////////////////////////////////// 00386 // Function: MayaNodeDesc::check_pseudo_joints 00387 // Access: Private 00388 // Description: Walks the hierarchy, looking for non-joint nodes that 00389 // are both children and parents of a joint. These 00390 // nodes are deemed to be pseudo joints, since the 00391 // converter must treat them as joints. 00392 //////////////////////////////////////////////////////////////////// 00393 void MayaNodeDesc:: 00394 check_pseudo_joints(bool joint_above) { 00395 static PN_uint32 space_count = 0; 00396 string space; 00397 for (PN_uint32 idx=0; idx<space_count; ++idx) { 00398 space.append(" "); 00399 } 00400 if (mayaegg_cat.is_spam()) { 00401 mayaegg_cat.spam() << "cpj:" << space << get_name() << " joint_type: " << _joint_type << endl; 00402 } 00403 if (_joint_type == JT_joint_parent && joint_above) { 00404 // This is one such node: it is the parent of a joint 00405 // (JT_joint_parent is set), and it is the child of a joint 00406 // (joint_above is set). 00407 _joint_type = JT_pseudo_joint; 00408 } 00409 00410 if (_joint_type == JT_joint) { 00411 // If this node is itself a joint, then joint_above is true for 00412 // all child nodes. 00413 joint_above = true; 00414 } 00415 00416 // Don't bother traversing further if _joint_type is none, since 00417 // that means this node has no joint children. 00418 if (_joint_type != JT_none) { 00419 00420 bool any_joints = false; 00421 Children::const_iterator ci; 00422 for (ci = _children.begin(); ci != _children.end(); ++ci) { 00423 MayaNodeDesc *child = (*ci); 00424 if (mayaegg_cat.is_spam()) { 00425 ++space_count; 00426 } 00427 child->check_pseudo_joints(joint_above); 00428 //if (child->is_joint()) { 00429 if (child->_joint_type == JT_joint || child->_joint_type == JT_pseudo_joint) { 00430 any_joints = true; 00431 } 00432 } 00433 00434 // If any children qualify as joints, then any sibling nodes that 00435 // are parents of joints are also elevated to joints. 00436 if (any_joints) { 00437 bool all_joints = true; 00438 for (ci = _children.begin(); ci != _children.end(); ++ci) { 00439 MayaNodeDesc *child = (*ci); 00440 MStatus status; 00441 MFnDagNode dag_node(child->get_dag_path(), &status); 00442 if (!status) { 00443 status.perror("MFnDagNode constructor"); 00444 } 00445 string type_name = dag_node.typeName().asChar(); 00446 if (child->_joint_type == JT_joint_parent) { 00447 child->_joint_type = JT_pseudo_joint; 00448 } else if (child->_joint_type == JT_none) { 00449 if (mayaegg_cat.is_spam()) { 00450 mayaegg_cat.spam() << "cpj: " << space << "jt_none for " << child->get_name() << endl; 00451 } 00452 if (type_name.find("transform") == string::npos) { 00453 if (mayaegg_cat.is_spam()) { 00454 mayaegg_cat.spam() << "cpj: " << space << "all_joints false for " << get_name() << endl; 00455 } 00456 all_joints = false; 00457 } 00458 } 00459 } 00460 00461 if (all_joints) { 00462 // Finally, if all children are joints, then we are too. 00463 if (_joint_type == JT_joint_parent) { 00464 if (!get_name().empty()) { // make sure parent of root is not a joint 00465 _joint_type = JT_pseudo_joint; 00466 } 00467 } 00468 } 00469 } 00470 } 00471 if (mayaegg_cat.is_spam()) { 00472 if (space_count > 0) 00473 --space_count; 00474 } 00475 } 00476 00477 //////////////////////////////////////////////////////////////////// 00478 // Function: MayaNodeDesc::check_blend_shapes 00479 // Access: Private 00480 // Description: Looks for blend shapes on a NURBS surface or polygon 00481 // mesh and records any blend shapes found. This is 00482 // similar to MayaToEggConverter::get_vertex_weights(), 00483 // which checks for membership of vertices to joints; 00484 // Maya stores the blend shape table in the same place. 00485 // See the comments in get_vertex_weights() for a more 00486 // in-depth description of the iteration process here. 00487 //////////////////////////////////////////////////////////////////// 00488 void MayaNodeDesc:: 00489 check_blend_shapes(const MFnDagNode &node, const string &attrib_name) { 00490 MStatus status; 00491 00492 MObject attr = node.attribute(attrib_name.c_str()); 00493 00494 MPlug history(node.object(), attr); 00495 MItDependencyGraph it(history, MFn::kDependencyNode, 00496 MItDependencyGraph::kUpstream, 00497 MItDependencyGraph::kDepthFirst, 00498 MItDependencyGraph::kNodeLevel); 00499 00500 while (!it.isDone()) { 00501 MObject c_node = it.thisNode(); 00502 00503 if (c_node.hasFn(MFn::kBlendShape)) { 00504 MFnBlendShapeDeformer blends(c_node, &status); 00505 if (!status) { 00506 status.perror("MFnBlendShapeDeformer constructor"); 00507 00508 } else { 00509 // Check if the slider is a "parallel blender", which is a 00510 // construct created by Maya for Maya's internal purposes 00511 // only. We don't want to fiddle with the parallel blenders. 00512 MPlug plug = blends.findPlug("pb"); 00513 bool is_parallel_blender; 00514 status = plug.getValue(is_parallel_blender); 00515 if (!status) { 00516 status.perror("Could not get value of pb plug."); 00517 is_parallel_blender = false; 00518 } 00519 00520 if (is_parallel_blender || 00521 _tree->ignore_slider(blends.name().asChar())) { 00522 _tree->report_ignored_slider(blends.name().asChar()); 00523 00524 } else { 00525 MObjectArray base_objects; 00526 status = blends.getBaseObjects(base_objects); 00527 if (!status) { 00528 status.perror("MFnBlendShapeDeformer::getBaseObjects"); 00529 } else { 00530 for (unsigned int oi = 0; oi < base_objects.length(); oi++) { 00531 MObject base_object = base_objects[oi]; 00532 00533 MIntArray index_list; 00534 status = blends.weightIndexList(index_list); 00535 if (!status) { 00536 status.perror("MFnBlendShapeDeformer::weightIndexList"); 00537 } else { 00538 for (unsigned int i = 0; i < index_list.length(); i++) { 00539 int wi = index_list[i]; 00540 PT(MayaBlendDesc) blend_desc = new MayaBlendDesc(blends, wi); 00541 blend_desc = _tree->add_blend_desc(blend_desc); 00542 _blend_descs.push_back(blend_desc); 00543 } 00544 } 00545 } 00546 } 00547 } 00548 } 00549 } 00550 00551 it.next(); 00552 } 00553 } 00554 00555 //////////////////////////////////////////////////////////////////// 00556 // Function: MayaNodeDesc::check_lods 00557 // Access: Private 00558 // Description: Walks through the hierarchy again and checks for LOD 00559 // specifications. Any such specifications found are 00560 // recorded on the child nodes of the lodGroups 00561 // themselves: the nodes that actually switch in and 00562 // out. (This is the way they are recorded in an egg 00563 // file.) 00564 //////////////////////////////////////////////////////////////////// 00565 void MayaNodeDesc:: 00566 check_lods() { 00567 // Walk through the children first. This makes it easier in the 00568 // below (we only have to return in the event of an error). 00569 Children::iterator ci; 00570 for (ci = _children.begin(); ci != _children.end(); ++ci) { 00571 MayaNodeDesc *child = (*ci); 00572 child->check_lods(); 00573 } 00574 00575 // Now consider whether this node is an lodGroup. 00576 if (_dag_path != (MDagPath *)NULL && 00577 _dag_path->hasFn(MFn::kLodGroup)) { 00578 // This node is a parent lodGroup; its children, therefore, are 00579 // LOD's. 00580 MStatus status; 00581 MFnDagNode dag_node(*_dag_path, &status); 00582 if (!status) { 00583 status.perror("Couldn't get node from dag path for lodGroup"); 00584 return; 00585 } 00586 00587 MPlug plug = dag_node.findPlug("threshold", &status); 00588 if (!status) { 00589 status.perror("Couldn't get threshold attributes on lodGroup"); 00590 return; 00591 } 00592 00593 // There ought to be the one fewer elements in the array than 00594 // there are children of the node. 00595 unsigned int num_elements = plug.numElements(); 00596 unsigned int num_children = _children.size(); 00597 if (num_elements + 1 != num_children) { 00598 mayaegg_cat.warning() 00599 << "Node " << get_name() << " has " << num_elements 00600 << " LOD entries, but " << num_children << " children.\n"; 00601 } 00602 00603 // Should we also consider cameraMatrix, to transform the LOD's 00604 // origin? It's not clear precisely what this transform matrix 00605 // means in Maya, so we'll wait until we have a sample file that 00606 // demonstrates its use. 00607 00608 double switch_out = 0.0; 00609 unsigned int i = 0; 00610 while (i < num_elements && i < num_children) { 00611 MPlug element = plug.elementByLogicalIndex(i); 00612 MayaNodeDesc *child = _children[i]; 00613 00614 double switch_in; 00615 status = element.getValue(switch_in); 00616 if (!status) { 00617 status.perror("Couldn't get double value from threshold."); 00618 return; 00619 } 00620 00621 child->_is_lod = true; 00622 child->_switch_in = switch_in; 00623 child->_switch_out = switch_out; 00624 00625 switch_out = switch_in; 00626 ++i; 00627 } 00628 00629 while (i < num_children) { 00630 // Also set the last child(ren). Maya wants this to switch in 00631 // at infinity, but Panda doesn't have such a concept; we'll 00632 // settle for four times the switch_out distance. 00633 MayaNodeDesc *child = _children[i]; 00634 child->_is_lod = true; 00635 child->_switch_in = switch_out * 4.0; 00636 child->_switch_out = switch_out; 00637 00638 ++i; 00639 } 00640 } 00641 }