diff --git a/pandatool/src/mayaegg/mayaToEggConverter.cxx b/pandatool/src/mayaegg/mayaToEggConverter.cxx index 0bca5491f9..ece3bd471f 100644 --- a/pandatool/src/mayaegg/mayaToEggConverter.cxx +++ b/pandatool/src/mayaegg/mayaToEggConverter.cxx @@ -70,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -1033,11 +1034,8 @@ make_nurbs_surface(const MDagPath &dag_path, MFnNurbsSurface &surface, return; } - /* - We don't use these variables currently. MFnNurbsSurface::Form u_form = surface.formInU(); MFnNurbsSurface::Form v_form = surface.formInV(); - */ int u_degree = surface.degreeU(); int v_degree = surface.degreeV(); @@ -1045,6 +1043,11 @@ make_nurbs_surface(const MDagPath &dag_path, MFnNurbsSurface &surface, int u_cvs = surface.numCVsInU(); 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. + 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; + int u_knots = surface.numKnotsInU(); int v_knots = surface.numKnotsInV(); @@ -1084,11 +1087,12 @@ make_nurbs_surface(const MDagPath &dag_path, MFnNurbsSurface &surface, if (!status) { status.perror("MPoint::get"); } else { - EggVertex vert; + EggVertex *vert = vpool->add_vertex(new EggVertex, i); LPoint4d p4d(v[0], v[1], v[2], v[3]); p4d = p4d * vertex_frame_inv; - vert.set_pos(p4d); - egg_nurbs->add_vertex(vpool->create_unique_vertex(vert)); + vert->set_pos(p4d); + + egg_nurbs->add_vertex(vert); } } @@ -1160,6 +1164,44 @@ make_nurbs_surface(const MDagPath &dag_path, MFnNurbsSurface &surface, if (shader != (MayaShader *)NULL) { set_shader_attributes(*egg_nurbs, *shader); } + + // Now try to find the skinning information for the surface. + bool got_weights = false; + + pvector joints; + MFloatArray weights; + if (_animation_convert == AC_model) { + got_weights = + get_vertex_weights(dag_path, surface, joints, weights); + } + + if (got_weights && !joints.empty()) { + int num_joints = joints.size(); + int num_weights = (int)weights.length(); + int num_verts = num_weights / num_joints; + // The number of weights should be an even multiple of verts * + // joints. + nassertv(num_weights == num_verts * num_joints); + + for (i = 0; i < egg_nurbs->get_num_cvs(); i++) { + int ui = egg_nurbs->get_u_index(i) % maya_u_cvs; + int vi = egg_nurbs->get_v_index(i) % maya_v_cvs; + + int maya_vi = maya_v_cvs * ui + vi; + nassertv(maya_vi < num_verts); + EggVertex *vert = vpool->get_vertex(i); + + for (int ji = 0; ji < num_joints; ++ji) { + float weight = weights[maya_vi * num_joints + ji]; + if (weight != 0.0f) { + EggGroup *joint = joints[ji]; + if (joint != (EggGroup *)NULL) { + joint->ref_vertex(vert, weight); + } + } + } + } + } } //////////////////////////////////////////////////////////////////// @@ -1684,6 +1726,7 @@ make_locator(const MDagPath &dag_path, const MFnDagNode &dag_node, egg_group->add_translate(p3d); } + //////////////////////////////////////////////////////////////////// // Function: MayaToEggConverter::get_vertex_weights // Access: Private @@ -1776,6 +1819,100 @@ get_vertex_weights(const MDagPath &dag_path, const MFnMesh &mesh, return false; } +//////////////////////////////////////////////////////////////////// +// Function: MayaToEggConverter::get_vertex_weights +// Access: Private +// Description: As above, for a NURBS surface instead of a polygon +// mesh. +//////////////////////////////////////////////////////////////////// +bool MayaToEggConverter:: +get_vertex_weights(const MDagPath &dag_path, const MFnNurbsSurface &surface, + pvector &joints, MFloatArray &weights) { + MStatus status; + + // Since we are working with a NURBS surface the input attribute that + // creates the surface is named "create" + // + MObject attr = surface.attribute("create"); + + // Create the plug to the "create" attribute then use the + // DG iterator to walk through the DG, at the node level. + // + MPlug history(surface.object(), attr); + MItDependencyGraph it(history, MFn::kDependencyNode, + MItDependencyGraph::kUpstream, + MItDependencyGraph::kDepthFirst, + MItDependencyGraph::kNodeLevel); + + while (!it.isDone()) { + // We will walk along the node level of the DG until we + // spot a skinCluster node. + // + MObject c_node = it.thisNode(); + if (c_node.hasFn(MFn::kSkinClusterFilter)) { + // We've found the cluster handle. Try to get the weight + // data. + // + MFnSkinCluster cluster(c_node, &status); + if (!status) { + status.perror("MFnSkinCluster constructor"); + return false; + } + + // Get the set of objects that influence the vertices of this + // surface. Hopefully these will all be joints. + MDagPathArray influence_objects; + cluster.influenceObjects(influence_objects, &status); + if (!status) { + status.perror("MFnSkinCluster::influenceObjects"); + + } else { + // Fill up the vector with the corresponding table of egg + // groups for each joint. + joints.clear(); + for (unsigned oi = 0; oi < influence_objects.length(); oi++) { + MDagPath joint_dag_path = influence_objects[oi]; + MayaNodeDesc *joint_node_desc = _tree.build_node(joint_dag_path); + EggGroup *joint = _tree.get_egg_group(joint_node_desc); + joints.push_back(joint); + } + + // Now use a component object to retrieve all of the weight + // data in one API call. + MFnDoubleIndexedComponent dic; + MObject dic_object = dic.create(MFn::kSurfaceCVComponent); + dic.setCompleteData(surface.numCVsInU(), surface.numCVsInV()); + unsigned influence_count; + + status = cluster.getWeights(dag_path, dic_object, + weights, influence_count); + if (!status) { + status.perror("MFnSkinCluster::getWeights"); + } else { + if (influence_count != influence_objects.length()) { + mayaegg_cat.error() + << "MFnSkinCluster::influenceObjects() returns " + << influence_objects.length() + << " objects, but MFnSkinCluster::getWeights() reports " + << influence_count << " objects.\n"; + + } else { + // We've got the weights and the set of objects. That's all + // we need. + return true; + } + } + } + } + + it.next(); + } + + // The surface was not soft-skinned. + return false; +} + + //////////////////////////////////////////////////////////////////// // Function: MayaShader::set_shader_attributes // Access: Private diff --git a/pandatool/src/mayaegg/mayaToEggConverter.h b/pandatool/src/mayaegg/mayaToEggConverter.h index b8a31855fe..91e9992339 100644 --- a/pandatool/src/mayaegg/mayaToEggConverter.h +++ b/pandatool/src/mayaegg/mayaToEggConverter.h @@ -122,6 +122,8 @@ private: EggGroup *egg_group); bool get_vertex_weights(const MDagPath &dag_path, const MFnMesh &mesh, pvector &joints, MFloatArray &weights); + bool get_vertex_weights(const MDagPath &dag_path, const MFnNurbsSurface &surface, + pvector &joints, MFloatArray &weights); void set_shader_attributes(EggPrimitive &primitive, const MayaShader &shader); void apply_texture_properties(EggTexture &tex,