support blend shapes

This commit is contained in:
David Rose 2004-02-11 17:47:30 +00:00
parent 1e11242da3
commit aa297d26ee
10 changed files with 499 additions and 19 deletions

View File

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

View File

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

View File

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

View File

@ -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 <maya/MFnBlendShapeDeformer.h>
#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

View File

@ -17,8 +17,17 @@
////////////////////////////////////////////////////////////////////
#include "mayaNodeDesc.h"
#include "mayaNodeTree.h"
#include "mayaBlendDesc.h"
#include "maya_funcs.h"
#include "pre_maya_include.h"
#include <maya/MFnBlendShapeDeformer.h>
#include <maya/MItDependencyGraph.h>
#include <maya/MFnNurbsSurface.h>
#include <maya/MFnMesh.h>
#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();
}
}

View File

@ -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 <maya/MDagPath.h>
#include <maya/MFnDagNode.h>
#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.

View File

@ -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);
}

View File

@ -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<string, MayaNodeDesc *> NodesByPath;
NodesByPath _nodes_by_path;
typedef pvector<MayaNodeDesc *> Nodes;
Nodes _nodes;
typedef ov_set<PT(MayaBlendDesc), IndirectCompareNames<MayaBlendDesc> > BlendDescs;
BlendDescs _blend_descs;
};
#endif

View File

@ -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 <maya/MFnSkinCluster.h>
#include <maya/MFnSingleIndexedComponent.h>
#include <maya/MFnDoubleIndexedComponent.h>
#include <maya/MFnBlendShapeDeformer.h>
#include <maya/MItDependencyGraph.h>
#include <maya/MDagPathArray.h>
#include <maya/MSelectionList.h>
@ -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("<skeleton>");
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<MPointArray> 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.

View File

@ -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,