diff --git a/pandatool/src/mayaegg/Sources.pp b/pandatool/src/mayaegg/Sources.pp index a2ef347359..36e450e0c1 100644 --- a/pandatool/src/mayaegg/Sources.pp +++ b/pandatool/src/mayaegg/Sources.pp @@ -17,6 +17,7 @@ #define SOURCES \ config_mayaegg.cxx config_mayaegg.h \ mayaEggGroupUserData.cxx mayaEggGroupUserData.I mayaEggGroupUserData.h \ + mayaBlendDesc.cxx mayaBlendDesc.h \ mayaNodeDesc.cxx mayaNodeDesc.h \ mayaNodeTree.cxx mayaNodeTree.h \ mayaToEggConverter.cxx mayaToEggConverter.h diff --git a/pandatool/src/mayaegg/config_mayaegg.cxx b/pandatool/src/mayaegg/config_mayaegg.cxx index 95d9620c5e..bc7a3104a1 100644 --- a/pandatool/src/mayaegg/config_mayaegg.cxx +++ b/pandatool/src/mayaegg/config_mayaegg.cxx @@ -19,6 +19,7 @@ #include "config_mayaegg.h" #include "mayaEggGroupUserData.h" #include "mayaNodeDesc.h" +#include "mayaBlendDesc.h" #include "dconfig.h" @@ -60,6 +61,7 @@ init_libmayaegg() { MayaEggGroupUserData::init_type(); MayaNodeDesc::init_type(); + MayaBlendDesc::init_type(); // For some reason, static init is not reliably running when this is // loaded as a plug-in of a plug-in. Initialize these explicitly diff --git a/pandatool/src/mayaegg/mayaBlendDesc.cxx b/pandatool/src/mayaegg/mayaBlendDesc.cxx new file mode 100644 index 0000000000..8bdd70c3b3 --- /dev/null +++ b/pandatool/src/mayaegg/mayaBlendDesc.cxx @@ -0,0 +1,80 @@ +// Filename: mayaBlendDesc.cxx +// Created by: drose (10Feb04) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "mayaBlendDesc.h" + +TypeHandle MayaBlendDesc::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: MayaBlendDesc::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +MayaBlendDesc:: +MayaBlendDesc(MFnBlendShapeDeformer deformer, int weight_index) : + _deformer(deformer), + _weight_index(weight_index) +{ + ostringstream strm; + strm << _deformer.name().asChar() << "." << _weight_index; + set_name(strm.str()); + + _anim = (EggSAnimData *)NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaBlendDesc::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +MayaBlendDesc:: +~MayaBlendDesc() { +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaBlendDesc::set_slider +// Access: Public +// Description: Moves the Maya slider associated with this blend +// shape to the indicated value. This will move all the +// affected vertices. +//////////////////////////////////////////////////////////////////// +void MayaBlendDesc:: +set_slider(float value) { + _deformer.setWeight(_weight_index, value); +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaBlendDesc::get_slider +// Access: Public +// Description: Returns the current position of the Maya slider +// associated with this blend shape. +//////////////////////////////////////////////////////////////////// +float MayaBlendDesc:: +get_slider() const { + return _deformer.weight(_weight_index); +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaBlendDesc::clear_egg +// Access: Private +// Description: Clears the egg pointers from this blend desc. +//////////////////////////////////////////////////////////////////// +void MayaBlendDesc:: +clear_egg() { + _anim = (EggSAnimData *)NULL; +} diff --git a/pandatool/src/mayaegg/mayaBlendDesc.h b/pandatool/src/mayaegg/mayaBlendDesc.h new file mode 100644 index 0000000000..8c699fe56b --- /dev/null +++ b/pandatool/src/mayaegg/mayaBlendDesc.h @@ -0,0 +1,81 @@ +// Filename: mayaBlendDesc.h +// Created by: drose (10Feb04) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef MAYABLENDDESC_H +#define MAYABLENDDESC_H + +#include "pandatoolbase.h" + +#include "referenceCount.h" +#include "pointerTo.h" +#include "namable.h" + +#include "pre_maya_include.h" +#include +#include "post_maya_include.h" + +class EggTable; +class EggSAnimData; + +//////////////////////////////////////////////////////////////////// +// Class : MayaBlendDesc +// Description : A handle to a Maya blend shape description. This is +// just one target of a Maya BlendShape object, and +// thus corresponds more or less one-to-one with a +// single Egg morph target. (We don't attempt to +// support Maya's chained target shapes here; should we +// need to later, it would mean breaking each of those +// target shapes on the one continuous Maya slider into +// a separate MayaBlendDesc object, and synthesizing the +// egg slider values appropriately.) +//////////////////////////////////////////////////////////////////// +class MayaBlendDesc : public ReferenceCount, public Namable { +public: + MayaBlendDesc(MFnBlendShapeDeformer deformer, int weight_index); + ~MayaBlendDesc(); + + void set_slider(float value); + float get_slider() const; + +private: + void clear_egg(); + + MFnBlendShapeDeformer _deformer; + int _weight_index; + + EggSAnimData *_anim; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + ReferenceCount::init_type(); + Namable::init_type(); + register_type(_type_handle, "MayaBlendDesc", + ReferenceCount::get_class_type(), + Namable::get_class_type()); + } + +private: + static TypeHandle _type_handle; + + friend class MayaNodeTree; +}; + +#endif diff --git a/pandatool/src/mayaegg/mayaNodeDesc.cxx b/pandatool/src/mayaegg/mayaNodeDesc.cxx index 8f4e7c7fa1..1dce67e594 100755 --- a/pandatool/src/mayaegg/mayaNodeDesc.cxx +++ b/pandatool/src/mayaegg/mayaNodeDesc.cxx @@ -17,8 +17,17 @@ //////////////////////////////////////////////////////////////////// #include "mayaNodeDesc.h" +#include "mayaNodeTree.h" +#include "mayaBlendDesc.h" #include "maya_funcs.h" +#include "pre_maya_include.h" +#include +#include +#include +#include +#include "post_maya_include.h" + TypeHandle MayaNodeDesc::_type_handle; // This is a list of the names of Maya connections that count as a @@ -41,8 +50,9 @@ static const int num_transform_connections = sizeof(transform_connections) / siz // Description: //////////////////////////////////////////////////////////////////// MayaNodeDesc:: -MayaNodeDesc(MayaNodeDesc *parent, const string &name) : +MayaNodeDesc(MayaNodeTree *tree, MayaNodeDesc *parent, const string &name) : Namable(name), + _tree(tree), _parent(parent) { _dag_path = (MDagPath *)NULL; @@ -73,11 +83,13 @@ MayaNodeDesc:: //////////////////////////////////////////////////////////////////// // Function: MayaNodeDesc::from_dag_path // Access: Public -// Description: Indicates an associated between the MayaNodeDesc and +// Description: Indicates an association between the MayaNodeDesc and // some Maya instance. //////////////////////////////////////////////////////////////////// void MayaNodeDesc:: from_dag_path(const MDagPath &dag_path) { + MStatus status; + if (_dag_path == (MDagPath *)NULL) { _dag_path = new MDagPath(dag_path); @@ -113,6 +125,18 @@ from_dag_path(const MDagPath &dag_path) { } } } + + if (dag_path.hasFn(MFn::kNurbsSurface)) { + MFnNurbsSurface surface(dag_path, &status); + if (status) { + check_blend_shapes(surface, "create"); + } + } else if (dag_path.hasFn(MFn::kMesh)) { + MFnMesh mesh(dag_path, &status); + if (status) { + check_blend_shapes(mesh, "inMesh"); + } + } } } @@ -140,6 +164,30 @@ get_dag_path() const { return *_dag_path; } +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeDesc::get_num_blend_descs +// Access: Public +// Description: Returns the number of unique MayaBlendDesc objects +// (and hence the number of morph sliders) that affect +// the geometry in this node. +//////////////////////////////////////////////////////////////////// +int MayaNodeDesc:: +get_num_blend_descs() const { + return _blend_descs.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeDesc::get_blend_desc +// Access: Public +// Description: Returns the nth MayaBlendDesc object that affects the +// geometry in this node. +//////////////////////////////////////////////////////////////////// +MayaBlendDesc *MayaNodeDesc:: +get_blend_desc(int n) const { + nassertr(n >= 0 && n < (int)_blend_descs.size(), NULL); + return _blend_descs[n]; +} + //////////////////////////////////////////////////////////////////// // Function: MayaNodeDesc::is_joint // Access: Public @@ -296,3 +344,63 @@ check_pseudo_joints(bool joint_above) { } } } + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeDesc::check_blend_shapes +// Access: Private +// Description: Looks for blend shapes on a NURBS surface or polygon +// mesh and records any blend shapes found. This is +// similar to MayaToEggConverter::get_vertex_weights(), +// which checks for membership of vertices to joints; +// Maya stores the blend shape table in the same place. +// See the comments in get_vertex_weights() for a more +// in-depth description of the iteration process here. +//////////////////////////////////////////////////////////////////// +void MayaNodeDesc:: +check_blend_shapes(const MFnDagNode &node, const string &attrib_name) { + MStatus status; + + MObject attr = node.attribute(attrib_name.c_str()); + + MPlug history(node.object(), attr); + MItDependencyGraph it(history, MFn::kDependencyNode, + MItDependencyGraph::kUpstream, + MItDependencyGraph::kDepthFirst, + MItDependencyGraph::kNodeLevel); + + while (!it.isDone()) { + MObject c_node = it.thisNode(); + + if (c_node.hasFn(MFn::kBlendShape)) { + MFnBlendShapeDeformer blends(c_node, &status); + if (!status) { + status.perror("MFnBlendShapeDeformer constructor"); + } else { + MObjectArray base_objects; + status = blends.getBaseObjects(base_objects); + if (!status) { + status.perror("MFnBlendShapeDeformer::getBaseObjects"); + } else { + for (unsigned int oi = 0; oi < base_objects.length(); oi++) { + MObject base_object = base_objects[oi]; + + MIntArray index_list; + status = blends.weightIndexList(index_list); + if (!status) { + status.perror("MFnBlendShapeDeformer::weightIndexList"); + } else { + for (unsigned int i = 0; i < index_list.length(); i++) { + int wi = index_list[i]; + PT(MayaBlendDesc) blend_desc = new MayaBlendDesc(blends, wi); + blend_desc = _tree->add_blend_desc(blend_desc); + _blend_descs.push_back(blend_desc); + } + } + } + } + } + } + + it.next(); + } +} diff --git a/pandatool/src/mayaegg/mayaNodeDesc.h b/pandatool/src/mayaegg/mayaNodeDesc.h index 65187b26a6..b20e793ed2 100755 --- a/pandatool/src/mayaegg/mayaNodeDesc.h +++ b/pandatool/src/mayaegg/mayaNodeDesc.h @@ -21,14 +21,17 @@ #include "pandatoolbase.h" +#include "mayaBlendDesc.h" #include "referenceCount.h" #include "pointerTo.h" #include "namable.h" #include "pre_maya_include.h" #include +#include #include "post_maya_include.h" +class MayaNodeTree; class EggGroup; class EggTable; class EggXfmSAnim; @@ -42,18 +45,23 @@ class EggXfmSAnim; //////////////////////////////////////////////////////////////////// class MayaNodeDesc : public ReferenceCount, public Namable { public: - MayaNodeDesc(MayaNodeDesc *parent = NULL, const string &name = string()); + MayaNodeDesc(MayaNodeTree *tree, + MayaNodeDesc *parent = NULL, const string &name = string()); ~MayaNodeDesc(); void from_dag_path(const MDagPath &dag_path); bool has_dag_path() const; const MDagPath &get_dag_path() const; + int get_num_blend_descs() const; + MayaBlendDesc *get_blend_desc(int n) const; + bool is_joint() const; bool is_joint_parent() const; bool is_tagged() const; + MayaNodeTree *_tree; MayaNodeDesc *_parent; typedef pvector< PT(MayaNodeDesc) > Children; Children _children; @@ -65,6 +73,8 @@ private: void clear_egg(); void mark_joint_parent(); void check_pseudo_joints(bool joint_above); + void check_blend_shapes(const MFnDagNode &node, + const string &attrib_name); MDagPath *_dag_path; @@ -72,6 +82,9 @@ private: EggTable *_egg_table; EggXfmSAnim *_anim; + typedef pvector< PT(MayaBlendDesc) > BlendDescs; + BlendDescs _blend_descs; + enum JointType { JT_none, // Not a joint. JT_joint, // An actual joint in Maya. diff --git a/pandatool/src/mayaegg/mayaNodeTree.cxx b/pandatool/src/mayaegg/mayaNodeTree.cxx index df2c4f0639..4891d3a204 100755 --- a/pandatool/src/mayaegg/mayaNodeTree.cxx +++ b/pandatool/src/mayaegg/mayaNodeTree.cxx @@ -17,12 +17,14 @@ //////////////////////////////////////////////////////////////////// #include "mayaNodeTree.h" +#include "mayaBlendDesc.h" #include "mayaEggGroupUserData.h" #include "config_mayaegg.h" #include "maya_funcs.h" #include "eggGroup.h" #include "eggTable.h" #include "eggXfmSAnim.h" +#include "eggSAnimData.h" #include "eggData.h" #include "dcast.h" @@ -40,11 +42,12 @@ //////////////////////////////////////////////////////////////////// MayaNodeTree:: MayaNodeTree() { - _root = new MayaNodeDesc; + _root = new MayaNodeDesc(this); _fps = 0.0; _egg_data = (EggData *)NULL; _egg_root = (EggGroupNode *)NULL; _skeleton_node = (EggGroupNode *)NULL; + _morph_node = (EggGroupNode *)NULL; } //////////////////////////////////////////////////////////////////// @@ -235,11 +238,12 @@ get_node(int n) const { //////////////////////////////////////////////////////////////////// void MayaNodeTree:: clear() { - _root = new MayaNodeDesc; + _root = new MayaNodeDesc(this); _fps = 0.0; _egg_data = (EggData *)NULL; _egg_root = (EggGroupNode *)NULL; _skeleton_node = (EggGroupNode *)NULL; + _morph_node = (EggGroupNode *)NULL; _nodes_by_path.clear(); _nodes.clear(); } @@ -253,11 +257,17 @@ clear() { //////////////////////////////////////////////////////////////////// void MayaNodeTree:: clear_egg(EggData *egg_data, EggGroupNode *egg_root, - EggGroupNode *skeleton_node) { + EggGroupNode *skeleton_node, EggGroupNode *morph_node) { _root->clear_egg(); + BlendDescs::iterator bi; + for (bi = _blend_descs.begin(); bi != _blend_descs.end(); ++bi) { + (*bi)->clear_egg(); + } + _egg_data = egg_data; _egg_root = egg_root; _skeleton_node = skeleton_node; + _morph_node = morph_node; } //////////////////////////////////////////////////////////////////// @@ -428,6 +438,88 @@ get_egg_anim(MayaNodeDesc *node_desc) { return node_desc->_anim; } +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeTree::get_egg_slider +// Access: Public +// Description: Returns the anim table corresponding to the slider +// for the indicated blend. Creates the table node if it +// has not already been created. +//////////////////////////////////////////////////////////////////// +EggSAnimData *MayaNodeTree:: +get_egg_slider(MayaBlendDesc *blend_desc) { + nassertr(_morph_node != (EggGroupNode *)NULL, NULL); + + if (blend_desc->_anim == (EggSAnimData *)NULL) { + // We need to make a new anim table. + EggSAnimData *egg_anim = new EggSAnimData(blend_desc->get_name()); + egg_anim->set_fps(_fps); + _morph_node->add_child(egg_anim); + + blend_desc->_anim = egg_anim; + } + + return blend_desc->_anim; +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeTree::add_blend_desc +// Access: Public +// Description: Adds the indicated MayaBlendDesc object to the list +// of blends collected so far. If a MayaBlendDesc +// object with the same name is already part of the +// tree, the supplied object is discarded and the +// previously-added object is returned; otherwise, the +// supplied object is added to the tree and the same +// object is returned. +// +// In either case, the return value is the MayaBlendDesc +// that should be used henceforth. +//////////////////////////////////////////////////////////////////// +MayaBlendDesc *MayaNodeTree:: +add_blend_desc(MayaBlendDesc *blend_desc) { + BlendDescs::iterator bi = _blend_descs.insert(blend_desc).first; + + return (*bi); +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeTree::get_num_blend_descs +// Access: Public +// Description: Returns the number of unique MayaBlendDesc objects +// (and hence the number of morph sliders) discovered in +// the tree. +//////////////////////////////////////////////////////////////////// +int MayaNodeTree:: +get_num_blend_descs() const { + return _blend_descs.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeTree::get_blend_desc +// Access: Public +// Description: Returns the nth MayaBlendDesc object discovered in +// the tree. +//////////////////////////////////////////////////////////////////// +MayaBlendDesc *MayaNodeTree:: +get_blend_desc(int n) const { + nassertr(n >= 0 && n < (int)_blend_descs.size(), NULL); + return _blend_descs[n]; +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeTree::reset_sliders +// Access: Public +// Description: Resets all of the sliders associated with all blend +// shapes down to 0. +//////////////////////////////////////////////////////////////////// +void MayaNodeTree:: +reset_sliders() { + BlendDescs::iterator bi; + for (bi = _blend_descs.begin(); bi != _blend_descs.end(); ++bi) { + (*bi)->set_slider(0.0); + } +} + //////////////////////////////////////////////////////////////////// // Function: MayaNodeTree::r_build_node @@ -465,7 +557,7 @@ r_build_node(const string &path) { } MayaNodeDesc *parent_node_desc = r_build_node(parent_path); - node_desc = new MayaNodeDesc(parent_node_desc, local_name); + node_desc = new MayaNodeDesc(this, parent_node_desc, local_name); _nodes.push_back(node_desc); } diff --git a/pandatool/src/mayaegg/mayaNodeTree.h b/pandatool/src/mayaegg/mayaNodeTree.h index fa21f84bc4..2477941d34 100755 --- a/pandatool/src/mayaegg/mayaNodeTree.h +++ b/pandatool/src/mayaegg/mayaNodeTree.h @@ -22,10 +22,16 @@ #include "pandatoolbase.h" #include "mayaNodeDesc.h" +#include "mayaBlendDesc.h" #include "globPattern.h" +#include "indirectCompareNames.h" +#include "ordered_vector.h" class EggData; class EggGroupNode; +class EggTable; +class EggXfmSAnim; +class EggSAnimData; //////////////////////////////////////////////////////////////////// // Class : MayaNodeTree @@ -47,26 +53,38 @@ public: void clear(); void clear_egg(EggData *egg_data, EggGroupNode *egg_root, - EggGroupNode *skeleton_node); + EggGroupNode *skeleton_node, EggGroupNode *morph_node); EggGroup *get_egg_group(MayaNodeDesc *node_desc); EggTable *get_egg_table(MayaNodeDesc *node_desc); EggXfmSAnim *get_egg_anim(MayaNodeDesc *node_desc); + EggSAnimData *get_egg_slider(MayaBlendDesc *blend_desc); + MayaBlendDesc *add_blend_desc(MayaBlendDesc *blend_desc); + int get_num_blend_descs() const; + MayaBlendDesc *get_blend_desc(int n) const; + + void reset_sliders(); + +public: PT(MayaNodeDesc) _root; float _fps; private: + MayaNodeDesc *r_build_node(const string &path); + EggData *_egg_data; EggGroupNode *_egg_root; EggGroupNode *_skeleton_node; - - MayaNodeDesc *r_build_node(const string &path); + EggGroupNode *_morph_node; typedef pmap NodesByPath; NodesByPath _nodes_by_path; typedef pvector Nodes; Nodes _nodes; + + typedef ov_set > BlendDescs; + BlendDescs _blend_descs; }; #endif diff --git a/pandatool/src/mayaegg/mayaToEggConverter.cxx b/pandatool/src/mayaegg/mayaToEggConverter.cxx index ece3bd471f..0744589c29 100644 --- a/pandatool/src/mayaegg/mayaToEggConverter.cxx +++ b/pandatool/src/mayaegg/mayaToEggConverter.cxx @@ -34,6 +34,7 @@ #include "eggTexture.h" #include "eggTextureCollection.h" #include "eggXfmSAnim.h" +#include "eggSAnimData.h" #include "string_utils.h" #include "dcast.h" @@ -71,6 +72,7 @@ #include #include #include +#include #include #include #include @@ -503,6 +505,11 @@ convert_char_model() { MGlobal::viewFrame(frame); } + // It's also important for us to reset all the blend shape sliders + // to 0 before we get out the model. Otherwise, the model we + // convert will have the current positions of the sliders baked in. + _tree.reset_sliders(); + EggGroup *char_node = new EggGroup(_character_name); get_egg_data().add_child(char_node); char_node->set_dart_type(EggGroup::DT_default); @@ -529,11 +536,13 @@ convert_char_chan(double start_frame, double end_frame, double frame_inc, root_table_node->add_child(bundle_node); EggTable *skeleton_node = new EggTable(""); bundle_node->add_child(skeleton_node); + EggTable *morph_node = new EggTable("morph"); + bundle_node->add_child(morph_node); // Set the frame rate before we start asking for anim tables to be // created. _tree._fps = output_frame_rate; - _tree.clear_egg(&get_egg_data(), NULL, skeleton_node); + _tree.clear_egg(&get_egg_data(), NULL, skeleton_node, morph_node); // Now we can get the animation data by walking through all of the // frames, one at a time, and getting the joint angles at each @@ -544,6 +553,7 @@ convert_char_chan(double start_frame, double end_frame, double frame_inc, PT(EggGroup) tgroup = new EggGroup; int num_nodes = _tree.get_num_nodes(); + int num_sliders = _tree.get_num_blend_descs(); int i; MTime frame(start_frame, MTime::uiUnit()); @@ -576,6 +586,16 @@ convert_char_chan(double start_frame, double end_frame, double frame_inc, } } + for (i = 0; i < num_sliders; i++) { + MayaBlendDesc *blend_desc = _tree.get_blend_desc(i); + if (mayaegg_cat.is_spam()) { + mayaegg_cat.spam() + << "slider " << blend_desc->get_name() << "\n"; + } + EggSAnimData *anim = _tree.get_egg_slider(blend_desc); + anim->add_data(blend_desc->get_slider()); + } + frame += frame_inc; } @@ -589,6 +609,12 @@ convert_char_chan(double start_frame, double end_frame, double frame_inc, } } + for (i = 0; i < num_sliders; i++) { + MayaBlendDesc *blend_desc = _tree.get_blend_desc(i); + EggSAnimData *anim = _tree.get_egg_slider(blend_desc); + anim->optimize(); + } + mayaegg_cat.info(false) << "\n"; @@ -605,7 +631,7 @@ bool MayaToEggConverter:: convert_hierarchy(EggGroupNode *egg_root) { int num_nodes = _tree.get_num_nodes(); - _tree.clear_egg(&get_egg_data(), egg_root, NULL); + _tree.clear_egg(&get_egg_data(), egg_root, NULL, NULL); for (int i = 0; i < num_nodes; i++) { MayaNodeDesc *node = _tree.get_node(i); if (!process_model_node(node)) { @@ -637,7 +663,7 @@ process_model_node(MayaNodeDesc *node_desc) { MFnDagNode dag_node(dag_path, &status); if (!status) { status.perror("MFnDagNode constructor"); - mayaegg_cat.error() << dag_path.fullPathName() << "\n"; + mayaegg_cat.error() << dag_path.fullPathName().asChar() << "\n"; return false; } @@ -701,7 +727,7 @@ process_model_node(MayaNodeDesc *node_desc) { << ":\n" << " it appears to have a NURBS surface, but does not.\n"; } else { - make_nurbs_surface(dag_path, surface, egg_group); + make_nurbs_surface(node_desc, dag_path, surface, egg_group); } } @@ -943,8 +969,8 @@ get_joint_transform(const MDagPath &dag_path, EggGroup *egg_group) { // indicated egg group. //////////////////////////////////////////////////////////////////// void MayaToEggConverter:: -make_nurbs_surface(const MDagPath &dag_path, MFnNurbsSurface &surface, - EggGroup *egg_group) { +make_nurbs_surface(MayaNodeDesc *node_desc, const MDagPath &dag_path, + MFnNurbsSurface &surface, EggGroup *egg_group) { MStatus status; string name = surface.name().asChar(); @@ -1022,6 +1048,31 @@ make_nurbs_surface(const MDagPath &dag_path, MFnNurbsSurface &surface, status.perror("MFnNurbsSurface::getCVs"); return; } + + // Also get out all the alternate blend shapes for the surface by + // applying each morph slider one at a time. + pvector morph_cvs; + if (_animation_convert == AC_model) { + int num_sliders = node_desc->get_num_blend_descs(); + morph_cvs.reserve(num_sliders); + for (int i = 0; i < num_sliders; i++) { + MayaBlendDesc *blend_desc = node_desc->get_blend_desc(i); + + // Temporarily push the slider up to 1.0 so we can see what the + // surface looks like at that value. + blend_desc->set_slider(1.0); + MPointArray cv_array; + status = surface.getCVs(cv_array, MSpace::kWorld); + blend_desc->set_slider(0.0); + + if (!status) { + status.perror("MFnNurbsSurface::getCVs"); + return; + } + morph_cvs.push_back(cv_array); + } + } + MDoubleArray u_knot_array, v_knot_array; status = surface.getKnotsInU(u_knot_array); if (!status) { @@ -1044,7 +1095,7 @@ make_nurbs_surface(const MDagPath &dag_path, MFnNurbsSurface &surface, int v_cvs = surface.numCVsInV(); // Maya repeats CVS at the end for a periodic surface, and doesn't - // count them in the weighted array, below. + // count them in the joint weight array, below. int maya_u_cvs = (u_form == MFnNurbsSurface::kPeriodic) ? u_cvs - u_degree : u_cvs; int maya_v_cvs = (v_form == MFnNurbsSurface::kPeriodic) ? v_cvs - v_degree : v_cvs; @@ -1081,9 +1132,10 @@ make_nurbs_surface(const MDagPath &dag_path, MFnNurbsSurface &surface, for (i = 0; i < egg_nurbs->get_num_cvs(); i++) { int ui = egg_nurbs->get_u_index(i); int vi = egg_nurbs->get_v_index(i); + int maya_vi = v_cvs * ui + vi; double v[4]; - MStatus status = cv_array[v_cvs * ui + vi].get(v); + status = cv_array[maya_vi].get(v); if (!status) { status.perror("MPoint::get"); } else { @@ -1092,6 +1144,28 @@ make_nurbs_surface(const MDagPath &dag_path, MFnNurbsSurface &surface, p4d = p4d * vertex_frame_inv; vert->set_pos(p4d); + // Now generate the morph targets for the vertex. + if (!morph_cvs.empty()) { + // Morph deltas are given in 3-d space, not in 4-d homogenous + // space. + LPoint3d p3d(v[0] / v[3], v[1] / v[3], v[2] / v[3]); + + for (unsigned int si = 0; si < morph_cvs.size(); si++) { + MayaBlendDesc *blend_desc = node_desc->get_blend_desc(si); + status = morph_cvs[si][maya_vi].get(v); + if (!status) { + status.perror("MPoint::get"); + } else { + LPoint3d m3d(v[0] / v[3], v[1] / v[3], v[2] / v[3]); + LVector3d delta = m3d - p3d; + if (!delta.almost_equal(LVector3d::zero())) { + EggMorphVertex dxyz(blend_desc->get_name(), delta); + vert->_dxyzs.insert(dxyz); + } + } + } + } + egg_nurbs->add_vertex(vert); } } @@ -1630,6 +1704,16 @@ make_polyset(const MDagPath &dag_path, const MFnMesh &mesh, pi.next(); } + // TODO: We also need to compute the vertex morphs for the polyset, + // based on whatever blend shapes may be present. This should be + // similar to the code in make_nurbs_surface(), except that since we + // don't have a one-to-one relationship of egg vertices to Maya + // vertices, we probably have to get the morphs down here, after we + // have added all of the egg vertices. I'll be happy to make this + // work as soon as someone gives me a sample Maya file that + // demonstrates blend shapes with polygon meshes. + + // Now that we've added all the polygons (and created all the // vertices), go back through the vertex pool and set up the // appropriate joint membership for each of the vertices. diff --git a/pandatool/src/mayaegg/mayaToEggConverter.h b/pandatool/src/mayaegg/mayaToEggConverter.h index 91e9992339..eb9c465080 100644 --- a/pandatool/src/mayaegg/mayaToEggConverter.h +++ b/pandatool/src/mayaegg/mayaToEggConverter.h @@ -104,7 +104,8 @@ private: // I ran into core dumps trying to pass around a MFnMesh object by // value. From now on, all MFn* objects will be passed around by // reference. - void make_nurbs_surface(const MDagPath &dag_path, + void make_nurbs_surface(MayaNodeDesc *node_desc, + const MDagPath &dag_path, MFnNurbsSurface &surface, EggGroup *group); EggNurbsCurve *make_trim_curve(const MFnNurbsCurve &curve,