//----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- MDagPath CVsSkinnerCmd::GetSpecifiedSkinnerNode() { MSelectionList skinnerNodes; MSelectionList optSelectionList; m_undo.ArgDatabase().getObjects( optSelectionList ); GetSpecifiedSkinnerNodes( optSelectionList, skinnerNodes ); MDagPath mDagPath; if ( skinnerNodes.length() == 0U ) return mDagPath; if ( skinnerNodes.length() > 1U ) { skinnerNodes.getDagPath( 0U, mDagPath ); mwarn << "Using vsSkinnerNode " << mDagPath.partialPathName() << ", ignoring extra vsSkinnerNode"; if ( skinnerNodes.length() > 2U ) mwarn << "s"; mwarn << ":"; for ( uint i( 1U ); i != skinnerNodes.length(); ++i ) { skinnerNodes.getDagPath( i, mDagPath ); mwarn << " " << mDagPath.partialPathName(); } mwarn << std::endl; } skinnerNodes.getDagPath( 0U, mDagPath ); return mDagPath; }
// // Write out a 'parent' command to parent one DAG node under another. // void maTranslator::writeParent( fstream& f, const MDagPath& parent, const MDagPath& child, bool addIt ) { f << "parent -s -nc -r "; // // If this is not the first parent then we have to include the "-a/add" // flag. // if (addIt) f << "-a "; // // If the parent is the world, then we must include the "-w/world" flag. // if (parent.length() == 0) f << "-w "; f << "\"" << child.partialPathName().asChar() << "\""; // // If the parent is NOT the world, then give the parent's name. // if (parent.length() != 0) f << " \"" << parent.partialPathName().asChar() << "\""; f << ";" << endl; }
// // Write out a 'createNode' command for a DAG node. // void maTranslator::writeCreateNode( fstream& f, const MDagPath& nodePath, const MDagPath& parentPath ) { MObject node(nodePath.node()); MFnDagNode nodeFn(node); // // Write out the 'createNode' command for this node. // f << "createNode " << nodeFn.typeName().asChar(); // // If the node is shared, then add a "-s/shared" flag to the command. // if (nodeFn.isShared()) f << " -s"; f << " -n \"" << nodeFn.name().asChar() << "\""; // // If this is not a top-level node, then include its first parent in the // command. // if (parentPath.length() > 0) f << " -p \"" << parentPath.partialPathName().asChar() << "\""; f << ";" << endl; }
//----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- MStatus CVsSkinnerCmd::DoLs() { MSelectionList tmpList; if ( m_undo.ArgDatabase().isFlagSet( kOptSelected ) ) { MSelectionList skinnerNodes; m_undo.ArgDatabase().getObjects( skinnerNodes ); GetSpecifiedSkinnerNodes( skinnerNodes, tmpList ); } else { MDagPath eDagPath; FindSkinnerNodesInHierarchy( eDagPath, tmpList ); } const bool longPath( m_undo.ArgDatabase().isFlagSet( kOptLong ) ); MStringArray result; MDagPath mDagPath; for ( MItSelectionList sIt( tmpList ); !sIt.isDone(); sIt.next() ) { if ( sIt.getDagPath( mDagPath ) ) { result.append( longPath ? mDagPath.fullPathName() : mDagPath.partialPathName() ); } } setResult( result ); return MS::kSuccess; }
//----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- MStatus CVsSkinnerCmd::DoCreate() { // Get name command line arg MString optName; if ( m_undo.ArgDatabase().isFlagSet( kOptName ) ) { m_undo.ArgDatabase().getFlagArgument( kOptName, 0, optName ); } // Create vsSkinner node MObject stObj; // Skinner transform object MObject vsSkinnerObj; // Skinner shape object MDagModifier &mDagModifier( m_undo.DagModifier() ); if ( vm::CreateDagNode( "vsSkinner", optName.length() ? optName.asChar() : GetName().asChar(), MObject ::kNullObj, &stObj, &vsSkinnerObj, &mDagModifier ) != MS::kSuccess ) { displayError( MString( "Couldn't create " ) + GetName() + " transform node" ); m_undo.Undo(); return MS::kFailure; } MDagPath stPath; MDagPath::getAPathTo( stObj, stPath ); setResult( stPath.partialPathName() ); MDagPath skinnerPath; MDagPath::getAPathTo( vsSkinnerObj, skinnerPath ); MSelectionList optSelectionList; m_undo.ArgDatabase().getObjects( optSelectionList ); MSelectionList volumeList( DoNewVolumes( skinnerPath, optSelectionList ) ); if ( volumeList.length() ) { MGlobal::setActiveSelectionList( volumeList, MGlobal::kReplaceList ); } else { MGlobal::select( stPath, MObject::kNullObj, MGlobal::kReplaceList ); } return MS::kSuccess; }
MStatus unShowAvailableSystems::findAvailableSystems(std::string& str,MDagPath& dagPath) { MStatus stat = MS::kSuccess; if(dagPath.hasFn(MFn::kJoint)) { MFnIkJoint jointFn(dagPath); std::string name = dagPath.partialPathName().asChar(); MPlug plug = jointFn.findPlug("unRibbonEnabled"); if(!plug.isNull()) { bool enabled; plug.getValue(enabled); char s[256]; sprintf(s,"%s RibbonSystem %s\n",name.c_str(),enabled ? "True" : "False"); str += s; } plug = jointFn.findPlug("unParticleEnabled"); if(!plug.isNull()) { bool enabled; plug.getValue(enabled); char s[256]; sprintf(s,"%s ParticleSystem %s\n",name.c_str(),enabled ? "True" : "False"); str += s; } } for (unsigned int i = 0; i < dagPath.childCount(); i++) { MObject child = dagPath.child(i); MDagPath childPath; stat = MDagPath::getAPathTo(child,childPath); if (MS::kSuccess != stat) { return MS::kFailure; } stat = findAvailableSystems(str,childPath); if (MS::kSuccess != stat) return MS::kFailure; } return MS::kSuccess; }
MStatus CMayaManager::BindViewerToPanel (const char* strView) { //HRESULT hr= S_OK; HWND renderwnd= NULL; MDagPath MayaCamera; if(strView == NULL) strView= ""; StringCchCopyA(m_ViewerBinding, MAX_PATH, strView); if(strView && (strView[0] != '\0')) { if(0 == lstrcmpiA(strView, "floating")) { g_Viewer.BindToWindow(NULL, true); } else { M3dView ourView; M3dView::get3dView(0,ourView); for(UINT iView= 0; iView < M3dView::numberOf3dViews(); iView++) { M3dView::get3dView(iView, ourView); ourView.getCamera(MayaCamera); MayaCamera.pop(); if(MayaCamera.partialPathName() == MString(strView)) { renderwnd= (HWND)ourView.window(); g_Viewer.BindToWindow(ourView.window(), true); break; } } } } //e_Exit: return MS::kSuccess; }
void Exporter::OutputSkinCluster(MObject& obj) { // attach a skin cluster function set to // access the data skinData SD; MFnSkinCluster fn(obj); MDagPathArray infs; //Get influences SD.influences = fn.influenceObjects(infs); // loop through the geometries affected by this cluster int nGeoms = fn.numOutputConnections(); for (int i = 0; i < nGeoms; ++i) { unsigned int index; index = fn.indexForOutputConnection(i); // get the dag path of the i'th geometry MDagPath skinPath; fn.getPathAtIndex(index, skinPath); // iterate through the components of this geometry MItGeometry gIter(skinPath); // print out the name of the skin cluster, // the vertexCount and the influenceCount cout << "Skin: " << skinPath.partialPathName().asChar() << endl; cout << "pointcount: " << gIter.count() << endl; cout << "numInfluences: " << SD.influences << endl; //Get points affected SD.points = gIter.count(); for (; !gIter.isDone(); gIter.next()) { MObject comp = gIter.component(); // Get the weights for this vertex (one per influence object) // MFloatArray wts; unsigned int infCount; fn.getWeights(skinPath, comp, wts, infCount); if (0 != infCount && !gIter.isDone()) { int numWeights = 0; float outWts[40] = { 1.0f, 0 }; int outInfs[40] = { 0 }; // Output the weight data for this vertex // for (int j = 0; j != infCount; ++j) { // ignore weights of little effect if (wts[j] > 0.001f) { if (numWeights != 0) { outWts[0] -= wts[j]; outWts[numWeights] = wts[j]; } outInfs[numWeights] = j; ++numWeights; } } float norm = outWts[0] + outWts[1] + outWts[2] + outWts[3]; MDagPath dag_path; MItDag dag_iter(MItDag::kBreadthFirst, MFn::kMesh); int currentmesh = 0, y = 0; while (!dag_iter.isDone()) { if (dag_iter.getPath(dag_path)) { MFnDagNode dag_node = dag_path.node(); if (!dag_node.isIntermediateObject()) { MFnMesh mesh(dag_path); if (!strcmp(skinPath.partialPathName().asChar(), mesh.partialPathName().asChar())) currentmesh = y; y++; } } dag_iter.next(); } for (int x = 0; x < 4; x++) { scene_.meshes[currentmesh].points[gIter.index()].boneIndices[x] = outInfs[x]; scene_.meshes[currentmesh].points[gIter.index()].boneWeigths[x] = outWts[x] / norm; } scene_.meshes[currentmesh].hasSkeleton = true; } } } }
MStatus exportJointClusterData::doIt( const MArgList& args ) // // Process the command // 1. parse the args // 2. find the jointClusters in the scene // 3. iterate over their members, writing their weight data out to file // { // parse args to get the file name from the command-line // MStatus stat = parseArgs(args); if (stat != MS::kSuccess) { return stat; } // count the processed jointClusters // unsigned int jcCount = 0; // Iterate through graph and search for jointCluster nodes // MItDependencyNodes iter( MFn::kJointCluster); for ( ; !iter.isDone(); iter.next() ) { MObject object = iter.item(); MFnWeightGeometryFilter jointCluster(object); // get the joint driving this cluster // MObject joint = jointForCluster(object); if (joint.isNull()) { displayError("Joint is not attached to cluster."); continue; } MObject deformSet = jointCluster.deformerSet(&stat); CheckError(stat,"Error getting deformer set."); MFnSet setFn(deformSet, &stat); //need the fn to get the members CheckError(stat,"Error getting deformer set fn."); MSelectionList clusterSetList; //get all the members // stat = setFn.getMembers(clusterSetList, true); CheckError(stat,"Could not make member list with getMembers."); // print out the name of joint and the number of associated skins // MFnDependencyNode fnJoint(joint); fprintf(file,"%s %u\n",fnJoint.name().asChar(), clusterSetList.length()); for (unsigned int kk = 0; kk < clusterSetList.length(); ++kk) { MDagPath skinpath; MObject components; MFloatArray weights; clusterSetList.getDagPath(kk,skinpath,components); jointCluster.getWeights(skinpath,components,weights); // print out the path name of the skin & the weight count // fprintf(file, "%s %u\n",skinpath.partialPathName().asChar(), weights.length()); // loop through the components and print their index and weight // unsigned counter =0; MItGeometry gIter(skinpath,components); for (/* nothing */ ; !gIter.isDone() && counter < weights.length(); gIter.next()) { fprintf(file,"%d %f\n",gIter.index(),weights[counter]); counter++; } } jcCount++; } fclose(file); if (0 == jcCount) { displayError("No jointClusters found in this scene."); return MS::kFailure; } return MS::kSuccess; }
HRESULT CMayaManager::PerspectiveCamera_Synchronize() { MDagPath MayaCamera; M3dView panel; for(UINT iView= 0; iView < M3dView::numberOf3dViews(); iView++) { D3DXMATRIX mCamera; M3dView::get3dView(iView, panel); panel.getCamera(MayaCamera); MayaCamera.pop(); MString perspNameStr( "persp" ); MString cameraNameStr = MayaCamera.partialPathName(); cameraNameStr = cameraNameStr.substring(0, perspNameStr.length()-1 ); const char* cameraName= cameraNameStr.asChar(); if(cameraNameStr == perspNameStr ) { MayaCamera.extendToShape(); MFloatMatrix fView(MayaCamera.inclusiveMatrix().matrix ); ConvertWorldMatrix(mCamera, fView); panel.getCamera(MayaCamera); MFnCamera fnMayaCamera(MayaCamera.node()); MVector mUp= fnMayaCamera.upDirection(); MVector mAt= fnMayaCamera.viewDirection(); MPoint mEye= fnMayaCamera.eyePoint(MSpace::kWorld); D3DXVECTOR3 dxEye( (float)mEye.x, (float)mEye.y, (float)-mEye.z ); D3DXVECTOR3 dxAt( (float)mAt.x, (float)mAt.y, (float)-mAt.z ); D3DXVECTOR3 dxUp( (float)mUp.x, (float)mUp.y, (float)-mUp.z ); D3DXVECTOR4 fEye; D3DXVECTOR4 fAt; D3DXVECTOR3 fUp; D3DXVec3Transform(&fEye, &dxEye,(D3DXMATRIX*)&mCamera); D3DXVec3Transform(&fAt, &dxAt,(D3DXMATRIX*)&mCamera); D3DXVec3TransformNormal(&fUp, &dxUp,(D3DXMATRIX*)&mCamera); D3DXMatrixLookAtLH(&PerspectiveCamera_View, (D3DXVECTOR3*)&fEye, (D3DXVECTOR3*)&fAt, &fUp); // Projection matrix float zNear = (float)fnMayaCamera.nearClippingPlane(); float zFar = (float)fnMayaCamera.farClippingPlane(); float hFOV = (float)fnMayaCamera.horizontalFieldOfView(); float f = (float) (1.0f / (float) tan( hFOV / 2.0f )); ZeroMemory( &PerspectiveCamera_Projection, sizeof(PerspectiveCamera_Projection) ); PerspectiveCamera_Projection._11 = f; PerspectiveCamera_Projection._22 = f; PerspectiveCamera_Projection._33 = (zFar+zNear) / (zFar-zNear); PerspectiveCamera_Projection._34 = 1.0f; PerspectiveCamera_Projection._43 = -2 * (zFar*zNear)/(zFar-zNear); break; } } return S_OK; }
MStatus mshUtil::doIt( const MArgList& args ) { MString objname, mcfname; MArgDatabase argData(syntax(), args); MSelectionList selList; MGlobal::getActiveSelectionList ( selList ); if ( selList.length() < 2 ) { MGlobal:: displayError ( "Not sufficient selection!" ); return MS::kSuccess; } MItSelectionList iter( selList ); iter.reset(); MDagPath meshPath; iter.getDagPath( meshPath ); meshPath.extendToShape(); MObject meshObj = meshPath.node(); MString surface = meshPath.partialPathName(); MStatus status; MFnMesh meshFn(meshPath, &status ); if(!status) { MGlobal:: displayError ( "Not sufficient selection!" ); return MS::kSuccess; } MPointArray vxa; meshFn.getPoints (vxa, MSpace::kWorld); MPoint cenfrom(0.f, 0.f, 0.f); for(unsigned i=0; i<vxa.length(); i++) cenfrom += vxa[i]; cenfrom = cenfrom/(float)vxa.length(); iter.next(); iter.getDagPath( meshPath ); meshPath.extendToShape(); MFnMesh mesh1Fn(meshPath, &status ); if(!status) { MGlobal:: displayError ( "Not sufficient selection!" ); return MS::kSuccess; } vxa.clear(); mesh1Fn.getPoints (vxa, MSpace::kWorld); MPoint cento(0.f, 0.f, 0.f); for(unsigned i=0; i<vxa.length(); i++) cento += vxa[i]; cento = cento/(float)vxa.length(); MVector diff = cento - cenfrom; MDoubleArray res; res.append(diff.x); res.append(diff.y); res.append(diff.z); setResult ( res ); /* if ( !argData.isFlagSet("-i") || !argData.isFlagSet("-o") ) { //MGlobal::displayError( "No .obj or .mcf file specified to translate! Example: mshUtil -i filename.obj -o filename.mcf" ); return MS::kSuccess; } else { argData.getFlagArgument("-i", 0, objname); argData.getFlagArgument("-o", 0, mcfname); return MS::kSuccess; } */ return MS::kSuccess; }
// -------------------------------------------------------------------- bool SceneGraph::getIsExportNode ( const MDagPath& dagPath, bool& isForced, bool& isVisible ) { // Does this dagPath already exist? If so, only recurse if FollowInstancedChildren() is set. MFnDagNode dagFn ( dagPath ); String dagNodeName = dagFn.name().asChar(); bool isSceneRoot = dagPath.length() == 0; // Ignore default and intermediate nodes (history items) bool isIntermediateObject = dagFn.isIntermediateObject(); if ( ( dagFn.isDefaultNode() && !isSceneRoot ) || isIntermediateObject ) { return false; } MString nodeName = dagPath.partialPathName(); if ( nodeName == MString ( NIMA_INTERNAL_PHYSIKS ) ) { // Skip this node, which is only used // by Nima as a work-around for a Maya bug. return false; } // If we are not already forcing this node, its children // check whether we should be forcing it (skinning of hidden joints). isForced = isForcedNode ( dagPath ); DagHelper::getPlugValue ( dagPath.node(), ATTR_VISIBILITY, isVisible ); bool isInstanced = dagPath.isInstanced(); uint instanceNumber = dagPath.instanceNumber(); if ( !isForced ) { // Check for visibility if ( !ExportOptions::exportInvisibleNodes() && !isVisible ) { // Check if the visibility of the element is animated. AnimationSampleCache* animationCache = mDocumentExporter->getAnimationCache(); if ( !AnimationHelper::isAnimated ( animationCache, dagPath.node(), ATTR_VISIBILITY ) ) { return false; } } else if ( !isVisible && !ExportOptions::exportDefaultCameras() ) { // Check for the default camera transform names. if ( nodeName == CAMERA_PERSP || nodeName == CAMERA_TOP || nodeName == CAMERA_SIDE || nodeName == CAMERA_FRONT || nodeName == CAMERA_PERSP_SHAPE || nodeName == CAMERA_TOP_SHAPE || nodeName == CAMERA_SIDE_SHAPE || nodeName == CAMERA_FRONT_SHAPE ) return false; } } isForced &= !isVisible; if ( !isForced ) { // We don't want to process manipulators if ( dagPath.hasFn ( MFn::kManipulator ) || dagPath.hasFn ( MFn::kViewManip ) ) return false; // Check for constraints which are not exported //if ( !ExportOptions::exportConstraints() && dagPath.hasFn ( MFn::kConstraint ) ) return false; if ( dagPath.hasFn ( MFn::kConstraint ) ) return false; // Check set membership exclusion/inclusion if ( SetHelper::isExcluded ( dagPath ) ) return false; } return true; }
MStatus Mesh::load(MDagPath& meshDag,MDagPath *pDagPath) { MStatus stat; std::vector<MFloatArray> weights; std::vector<MIntArray> Ids; std::vector<MIntArray> jointIds; unsigned int numJoints = 0; std::vector<vertexInfo> vertices; MFloatPointArray points; MFloatVectorArray normals; if (!meshDag.hasFn(MFn::kMesh)) return MS::kFailure; MFnMesh mesh(meshDag); /*{ mesh.getPoints(points,MSpace::kWorld); MPoint pos; mesh.getPoint(1,pos,MSpace::kWorld); for(unsigned i = 0;i < points.length();i++) { MFloatPoint fp = points[i]; float x = fp.x; float y = fp.y; float z = fp.z; fp = fp; } }*/ int numVertices = mesh.numVertices(); vertices.resize(numVertices); weights.resize(numVertices); Ids.resize(numVertices); jointIds.resize(numVertices); // 获取UV坐标集的名称 MStringArray uvsets; int numUVSets = mesh.numUVSets(); if (numUVSets > 0) { stat = mesh.getUVSetNames(uvsets); if (MS::kSuccess != stat) { std::cout << "Error retrieving UV sets names\n"; return MS::kFailure; } } // 保存UV集信息 for (int i=m_uvsets.size(); i<uvsets.length(); i++) { uvset uv; uv.size = 2; uv.name = uvsets[i].asChar(); m_uvsets.push_back(uv); } MStringArray colorSetsNameArray; m_colorSets.clear(); int numColorSets = mesh.numColorSets(); if (numColorSets > 0) { mesh.getColorSetNames(colorSetsNameArray); } for (int i = 0; i != colorSetsNameArray.length(); ++i) { std::string name = colorSetsNameArray[i].asChar(); m_colorSets.push_back(name); } // 检查法线是否反 bool opposite = false; mesh.findPlug("opposite",true).getValue(opposite); // get connected skin cluster (if present) bool foundSkinCluster = false; MItDependencyNodes kDepNodeIt( MFn::kSkinClusterFilter ); for( ;!kDepNodeIt.isDone() && !foundSkinCluster; kDepNodeIt.next()) { MObject kObject = kDepNodeIt.item(); m_pSkinCluster = new MFnSkinCluster(kObject); unsigned int uiNumGeometries = m_pSkinCluster->numOutputConnections(); for(unsigned int uiGeometry = 0; uiGeometry < uiNumGeometries; ++uiGeometry ) { unsigned int uiIndex = m_pSkinCluster->indexForOutputConnection(uiGeometry); MObject kOutputObject = m_pSkinCluster->outputShapeAtIndex(uiIndex); if(kOutputObject == mesh.object()) { foundSkinCluster = true; } else { delete m_pSkinCluster; m_pSkinCluster = NULL; } } // load connected skeleton (if present) if (m_pSkinCluster) { if (!m_pSkeleton) m_pSkeleton = new skeleton(); stat = m_pSkeleton->load(m_pSkinCluster); if (MS::kSuccess != stat) std::cout << "Error loading skeleton data\n"; } else { // breakable; } } // get connected shaders MObjectArray shaders; MIntArray shaderPolygonMapping; stat = mesh.getConnectedShaders(0,shaders,shaderPolygonMapping); if (MS::kSuccess != stat) { std::cout << "Error getting connected shaders\n"; return MS::kFailure; } if (shaders.length() <= 0) { std::cout << "No connected shaders, skipping mesh\n"; return MS::kFailure; } // create a series of arrays of faces for each different submesh std::vector<faceArray> polygonSets; polygonSets.resize(shaders.length()); // Get faces data // prepare vertex table for (int i=0; i<vertices.size(); i++) vertices[i].next = -2; //get vertex positions from mesh data mesh.getPoints(points,MSpace::kWorld); mesh.getNormals(normals,MSpace::kWorld); //get list of vertex weights if (m_pSkinCluster) { MItGeometry iterGeom(meshDag); for (int i=0; !iterGeom.isDone(); iterGeom.next(), i++) { weights[i].clear(); Ids[i].clear(); MObject component = iterGeom.component(); MFloatArray vertexWeights; stat=m_pSkinCluster->getWeights(meshDag,component,vertexWeights,numJoints); int nWeights = vertexWeights.length(); for(int j = 0;j<nWeights;j++) { if(vertexWeights[j] >= 0.00001f || vertexWeights[j] <= -0.00001f ) { // 记录该节点j Ids[i].append(j); weights[i].append(vertexWeights[j]); } } //weights[i]= vertexWeights; if (MS::kSuccess != stat) { std::cout << "Error retrieving vertex weights\n"; } // get ids for the joints if (m_pSkeleton) { jointIds[i].clear(); if(weights[i].length() > 0 ) { MDagPathArray influenceObjs; m_pSkinCluster->influenceObjects(influenceObjs,&stat); if (MS::kSuccess != stat) { std::cout << "Error retrieving influence objects for given skin cluster\n"; } jointIds[i].setLength(weights[i].length()); for (int j=0; j<jointIds[i].length(); j++) { bool foundJoint = false; for (int k=0; k<m_pSkeleton->getJoints().size() && !foundJoint; k++) { if (influenceObjs[Ids[i][j]].partialPathName() == m_pSkeleton->getJoints()[k].name) { foundJoint=true; jointIds[i][j] = m_pSkeleton->getJoints()[k].id; } } } } } } } // create an iterator to go through mesh polygons if (mesh.numPolygons() > 0) { const char *name = mesh.name().asChar(); MItMeshPolygon faceIter(mesh.object(),&stat); if (MS::kSuccess != stat) { std::cout << "Error accessing mesh polygons\n"; return MS::kFailure; } // iterate over mesh polygons for (; !faceIter.isDone(); faceIter.next()) { int numTris=0; faceIter.numTriangles(numTris); // for every triangle composing current polygon extract triangle info for (int iTris=0; iTris<numTris; iTris++) { MPointArray triPoints; MIntArray tempTriVertexIdx,triVertexIdx; int idx; // create a new face to store triangle info face newFace; // extract triangle vertex indices faceIter.getTriangle(iTris,triPoints,tempTriVertexIdx); // convert indices to face-relative indices MIntArray polyIndices; faceIter.getVertices(polyIndices); unsigned int iPoly, iObj; for (iObj=0; iObj < tempTriVertexIdx.length(); ++iObj) { // iPoly is face-relative vertex index for (iPoly=0; iPoly < polyIndices.length(); ++iPoly) { if (tempTriVertexIdx[iObj] == polyIndices[iPoly]) { triVertexIdx.append(iPoly); break; } } } // iterate over triangle's vertices for (int i=0; i<3; i++) { bool different = true; int vtxIdx = faceIter.vertexIndex(triVertexIdx[i]); int nrmIdx = faceIter.normalIndex(triVertexIdx[i]); // get vertex color MColor color; if (faceIter.hasColor(triVertexIdx[i])) { //This method gets the average color of the all the vertices in this face stat = faceIter.getColor(color,triVertexIdx[i]); if (MS::kSuccess != stat) { color = MColor(1,1,1,1); } if (color.r > 1) color.r = 1; if (color.g > 1) color.g = 1; if (color.b > 1) color.b = 1; if (color.a > 1) color.a = 1; } else { color = MColor(1,1,1,1); } if (vertices[vtxIdx].next == -2) // first time we encounter a vertex in this position { // save vertex position points[vtxIdx].cartesianize(); vertices[vtxIdx].pointIdx = vtxIdx; // save vertex normal vertices[vtxIdx].normalIdx = nrmIdx; // save vertex colour vertices[vtxIdx].r = color.r; vertices[vtxIdx].g = color.g; vertices[vtxIdx].b = color.b; vertices[vtxIdx].a = color.a; // save vertex texture coordinates vertices[vtxIdx].u.resize(uvsets.length()); vertices[vtxIdx].v.resize(uvsets.length()); // save vbas vertices[vtxIdx].vba.resize(weights[vtxIdx].length()); for (int j=0; j<weights[vtxIdx].length(); j++) { vertices[vtxIdx].vba[j] = (weights[vtxIdx])[j]; } // save joint ids vertices[vtxIdx].jointIds.resize(jointIds[vtxIdx].length()); for (int j=0; j<jointIds[vtxIdx].length(); j++) { vertices[vtxIdx].jointIds[j] = (jointIds[vtxIdx])[j]; } // save uv sets data for (int j=0; j<uvsets.length(); j++) { float2 uv; stat = faceIter.getUV(triVertexIdx[i],uv,&uvsets[j]); if (MS::kSuccess != stat) { uv[0] = 0; uv[1] = 0; } vertices[vtxIdx].u[j] = uv[0]; vertices[vtxIdx].v[j] = (-1)*(uv[1]-1); } // save vertex index in face info newFace.v[i] = vtxIdx; // update value of index to next vertex info (-1 means nothing next) vertices[vtxIdx].next = -1; } else // already found at least 1 vertex in this position { // check if a vertex with same attributes has been saved already for (int k=vtxIdx; k!=-1 && different; k=vertices[k].next) { different = false; MFloatVector n1 = normals[vertices[k].normalIdx]; MFloatVector n2 = normals[nrmIdx]; if (n1.x!=n2.x || n1.y!=n2.y || n1.z!=n2.z) { different = true; } if (vertices[k].r!=color.r || vertices[k].g!=color.g || vertices[k].b!= color.b || vertices[k].a!=color.a) { different = true; } for (int j=0; j<uvsets.length(); j++) { float2 uv; stat = faceIter.getUV(triVertexIdx[i],uv,&uvsets[j]); if (MS::kSuccess != stat) { uv[0] = 0; uv[1] = 0; } uv[1] = (-1)*(uv[1]-1); if (vertices[k].u[j]!=uv[0] || vertices[k].v[j]!=uv[1]) { different = true; } } idx = k; } // if no identical vertex has been saved, then save the vertex info if (different) { vertexInfo vtx; // save vertex position vtx.pointIdx = vtxIdx; // save vertex normal vtx.normalIdx = nrmIdx; // save vertex colour vtx.r = color.r; vtx.g = color.g; vtx.b = color.b; vtx.a = color.a; // save vertex vba vtx.vba.resize(weights[vtxIdx].length()); for (int j=0; j<weights[vtxIdx].length(); j++) { vtx.vba[j] = (weights[vtxIdx])[j]; } // save joint ids vtx.jointIds.resize(jointIds[vtxIdx].length()); for (int j=0; j<jointIds[vtxIdx].length(); j++) { vtx.jointIds[j] = (jointIds[vtxIdx])[j]; } // save vertex texture coordinates vtx.u.resize(uvsets.length()); vtx.v.resize(uvsets.length()); for (int j=0; j<uvsets.length(); j++) { float2 uv; stat = faceIter.getUV(triVertexIdx[i],uv,&uvsets[j]); if (MS::kSuccess != stat) { uv[0] = 0; uv[1] = 0; } vtx.u[j] = uv[0]; vtx.v[j] = (-1)*(uv[1]-1); } vtx.next = -1; vertices.push_back(vtx); // save vertex index in face info newFace.v[i] = vertices.size()-1; vertices[idx].next = vertices.size()-1; } else { newFace.v[i] = idx; } } } // end iteration of triangle vertices // add face info to the array corresponding to the submesh it belongs // skip faces with no shaders assigned if (shaderPolygonMapping[faceIter.index()] >= 0) polygonSets[shaderPolygonMapping[faceIter.index()]].push_back(newFace); } // end iteration of triangles } } std::cout << "done reading mesh triangles\n"; // create a submesh for every different shader linked to the mesh unsigned shaderLength = shaders.length(); for (int i=0; i<shaderLength; i++) { // check if the submesh has at least 1 triangle if (polygonSets[i].size() > 0) { //create new submesh SubMesh* pSubmesh = new SubMesh(); const char *nm = mesh.name().asChar(); const char *nm1 = mesh.partialPathName().asChar(); const char *nm2 = mesh.parentNamespace().asChar(); const char *nm3 = mesh.fullPathName().asChar(); const char *nm4 = meshDag.fullPathName().asChar(); pSubmesh->m_name = meshDag.partialPathName(); if(pDagPath) pSubmesh->m_name = pDagPath->partialPathName(); const char *szName = pSubmesh->m_name.asChar(); if(shaderLength > 1) { char a[256]; sprintf(a,"%d",i); pSubmesh->m_name += a; } OutputDebugString(pSubmesh->m_name.asChar()); OutputDebugString("\n"); //OutputDebugString(szName); //OutputDebugString("\n"); //load linked shader stat = pSubmesh->loadMaterial(shaders[i],uvsets); if (stat != MS::kSuccess) { MFnDependencyNode shadingGroup(shaders[i]); std::cout << "Error loading submesh linked to shader " << shadingGroup.name().asChar() << "\n"; return MS::kFailure; } //load vertex and face data stat = pSubmesh->load(polygonSets[i],vertices,points,normals,opposite); //add submesh to current mesh m_submeshes.push_back(pSubmesh); } } return MS::kSuccess; }
MStatus cgfxShaderCmd::doCmd(const MArgList& args) // // Description: // implements the MEL cgfxShader command. // // Arguments: // -fx/fxFile The CgFX file to load. // -e/edit Edit an existing cgfxShader rather than creating // a new one. // -q/query Get specified info // // Return Value: // MS::kSuccess - command succeeded // MS::kFailure - command failed (returning this value will cause the // MEL script that is being run to terminate unless the // error is caught using a "catch" statement. // { // Get the current state of the flag // and store it in a temporary variable // static int tmpFlag = -1; #if defined(_WIN32) && defined(CGFX_DEBUG_MEMORY) if (tmpFlag == -1) { tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ); // Turn On (OR) - call _CrtCheckMemory at every // allocation request tmpFlag |= _CRTDBG_CHECK_ALWAYS_DF; // Turn on (OR) - check for memory leaks at end // of program. tmpFlag |= _CRTDBG_LEAK_CHECK_DF; _CrtSetDbgFlag( tmpFlag ); } #endif /* _WIN32 && CGFX_DEBUG_MEMORY */ MStatus status; MSelectionList selList; MObject oNode; MString sResult; MStringArray saResult; MString sFeedback; MString sTemp; MString sWho = "cgfxShader : "; status = parseArgs(args, selList); if (!status) { return status; } // -pp / -pluginPath // Returns the directory path where this plug-in's auxiliary // files, such as MEL scripts, are expected to be found. // The path name is in Maya format ('/' delimited) with no // trailing slash. Result type is string. (Query only) if ( fPluginPath ) { setResult( sPluginPath ); return MS::kSuccess; } // -lp / -listProfiles // // Return the names of the profiles supported on the current // platform. // // Each item in the result array has the form // "VertexProfileName<,GeometryProfileName,FragmentProfileName" // // Result type is string[]. (Query only; set internally) if ( fListProfiles ) { setResult( cgfxProfile::getProfileList() ); return status; } // -mtc / -maxTexCoords // Returns the maximum number of texcoord inputs that can be // passed to vertex shaders under the currently installed // OpenGL implementation. Returns 0 if the information is // not available. Result type is integer. (Query only) // // Don't use GL_MAX_TEXTURE_UNITS as this does not provide a proper // count when the # of image or texcoord inputs differs // from the conventional (older) notion of texture unit. // // Instead take the minimum of GL_MAX_TEXTURE_COORDS_ARB and // GL_MAX_TEXUTRE_IMAGE_UNITS_ARB according to the // ARB_FRAGMENT_PROGRAM specification. if ( fMaxTexCoords ) { GLint mtc = 0; M3dView vw = M3dView::active3dView( &status ); if ( status && vw.beginGL() ) { glGetIntegerv( GL_MAX_TEXTURE_COORDS_ARB, &mtc ); GLint mic = 0; glGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &mic ); if (mic < mtc) mtc = mic; if ( mtc < 1 ) mtc = 1; else if ( mtc > CGFXSHADERNODE_GL_TEXTURE_MAX ) mtc = CGFXSHADERNODE_GL_TEXTURE_MAX; vw.endGL(); } setResult( (int)mtc ); return MS::kSuccess; } // If edit or query, find the specified cgfxShaderNode. MFnDependencyNode fnNode; cgfxShaderNode* pNode = NULL; if ( fIsEdit || fIsQuery ) { // We are editing an existing node which must have been // provided in the args (or the current selection list). // Get the correct node name into fNodeName; // if (selList.length() != 1) { status = MS::kNotFound; return status; } // Get the name of the node into fNodeName so that it can // be saved for undo/redo // MStringArray tmpList; selList.getSelectionStrings(tmpList); fNodeName = tmpList[0]; if ( fNodeName.length() ) { sWho += " \""; sWho += fNodeName; sWho += "\""; } status = selList.getDependNode(0, oNode); if (!status) { return status; } status = fnNode.setObject( oNode ); if (!status) { sFeedback = sWho; sFeedback += " is not a cgfxShader node."; MGlobal::displayError( sFeedback ); return status; } if (fnNode.typeId() != cgfxShaderNode::sId) { status = MS::kInvalidParameter; sFeedback = sWho; sFeedback += " is not a cgfxShader node."; MGlobal::displayError( sFeedback ); return status; } pNode = (cgfxShaderNode*)fnNode.userNode(); if (!pNode) { status = MS::kInvalidParameter; sFeedback = sWho; sFeedback += " is not cgfxShader node."; MGlobal::displayError( sFeedback ); return status; } } if ( fIsQuery ) { // -fx / -fxFile // Returns the shader file name. if ( fFxFile ) { MString path = pNode->shaderFxFile(); setResult( path ); return MS::kSuccess; } // -fxp / -fxPath // Returns the path of the fx file. The path name is in Maya // format ('/' delimited). Result type is string. // (Query only) if ( fFxPath ) { MString path = cgfxFindFile(pNode->shaderFxFile()); setResult( path ); return MS::kSuccess; } // -t / -technique // Returns the currently active technique if ( fTechnique ) { MString path = pNode->getTechnique(); setResult( path ); return MS::kSuccess; } // -p / -profile // Returns the current profile if ( fProfile ) { MString path = pNode->getProfile(); setResult( path ); return MS::kSuccess; } // -lt / -listTechniques // Return the technique names defined by the current effect. // // Each item in the result array has the form // "techniqueName<TAB>numPasses" // where // numPasses is the number of passes defined by the // technique, or 0 if the technique is not valid. // (Future versions of the cgfxShader plug-in may append // additional tab-separated fields.) // // Result type is string[]. (Query only; set internally) if ( fListTechniques ) { setResult( pNode->getTechniqueList() ); return status; } // -lp / -listParameters // Return the attribute names corresponding to the // shader's tweakable uniform parameters. // Result type is string[]. (Query only; set internally) // -des / -description // If specified, each item in the result array has the form // "attrName<TAB>type<TAB>semantic<TAB>description<TAB>extraAttrSuffix" // (Future versions of the cgfxShader plug-in may provide // additional tab-separated fields after the semantic.) // A missing field is indicated by a single space (" ") // so the string can be parsed more easily using the MEL // "tokenize" function, which treats a group of consecutive // delimiters the same as a single delimiter. if ( fListParameters ) { cgfxRCPtr<cgfxAttrDefList> list = cgfxAttrDef::attrsFromNode( oNode ); for ( cgfxAttrDefList::iterator it = list; it; ++it ) { cgfxAttrDef* aDef = *it; if ( fDescription ) { sResult = aDef->fName.length() ? aDef->fName : " "; sResult += "\t"; sTemp = aDef->typeName(); sResult += sTemp.length() ? sTemp : " "; sResult += "\t"; sResult += aDef->fSemantic.length() ? aDef->fSemantic : " "; sResult += "\t"; sResult += aDef->fDescription.length() ? aDef->fDescription : " "; sResult += "\t"; const char* suffix = aDef->getExtraAttrSuffix(); sResult += suffix ? suffix : " "; } else sResult = aDef->fName; saResult.append( sResult ); } setResult( saResult ); return status; } // -p / -parameter <name> // Return a string describing the data type and usage of // the attribute whose name is specified. // Result type is string (with no -description flag), or // string array (if you specify -description). // (Query only; set internally) // -ci / -caseInsensitive // If specified, returns information for the first // attribute that matches the specified name assuming // no distinction between upper and lower case letters. // -des / -description // If specified, the result is a string array containing: // [0] = attribute name // [1] = type // [2] = semantic // [3] = description from "desc" or "uiname" annotation // [4] = extra attribute suffix for Vector4 ("W") / Color4 ("Alpha") // (Future versions of the cgfxShader plug-in may provide // additional tab-separated fields after the semantic.) // If omitted, only the type is returned (a string). if ( fParameterName.length() > 0 ) { cgfxRCPtr<cgfxAttrDefList> list = cgfxAttrDef::attrsFromNode( oNode ); cgfxAttrDefList::iterator it; if ( fCaseInsensitive ) it = list->findInsensitive( fParameterName ); else it = list->find( fParameterName ); if ( fDescription ) { if ( it ) { cgfxAttrDef* aDef = *it; saResult.append( aDef->fName ); saResult.append( aDef->typeName() ); saResult.append( aDef->fSemantic ); saResult.append( aDef->fDescription ); const char* suffix = aDef->getExtraAttrSuffix(); saResult.append( suffix ? suffix : "" ); } setResult( saResult ); } else { if ( it ) sResult = (*it)->typeName(); setResult( sResult ); } return status; } // -euv / -emptyUV // Returns the names of blacklisted UV sets. These UV sets // are disabled from being passed to the shader because there // is at least one mesh where the UV set name is defined but // has no faces mapped. Due to a bug in Maya (in 5.0 and // possibly some other releases), Maya crashes if an empty // UV set is accessed by a hardware shader. Blacklisting is // intended to protect the user against accidentally hitting // the bug and crashing Maya. After the Maya fix has been // verified, this option can continue to be accepted for awhile // for compatibility, returning an empty result array. // Result type is string[]. (Query only; set internally) if ( fEmptyUV ) { setResult( pNode->getEmptyUVSets() ); return MS::kSuccess; } // -eus / -emptyUVShapes // Returns the names of shape nodes that have empty UV sets // which are causing the UV set names to be blacklisted. // After the Maya bug fix has been verified, this option // can remain for awhile for compatibility, returning an // empty result array. // Result type is string[]. (Query only; set internally) if ( fEmptyUVShapes ) { const MObjectArray& oaShapes = pNode->getEmptyUVSetShapes(); MFnDagNode fnDagNode; MDagPath dpShape; for ( unsigned iShape = 0; iShape < oaShapes.length(); ++iShape ) { fnDagNode.setObject( oaShapes[ iShape ] ); fnDagNode.getPath( dpShape ); saResult.append( dpShape.partialPathName() ); } setResult( saResult ); return MS::kSuccess; } // -tcs / -texCoordSource // Returns the value of the texCoordSource attribute, because // the MEL "getAttr" command doesn't work with string arrays. // Result type is string[]. (Query only; set via "setAttr") if ( fTexCoordSource ) { setResult( pNode->getTexCoordSource() ); return MS::kSuccess; } #if MAYA_API_VERSION >= 700 // -cs / -colorSource // Returns the value of the colorSource attribute, because // the MEL "getAttr" command doesn't work with string arrays. // Result type is string[]. (Query only; set via "setAttr") if ( fColorSource ) { setResult( pNode->getColorSource() ); return MS::kSuccess; } #endif // Error if -q with no other query flags. return MS::kInvalidParameter; } // If user didn't specify shader fx file, default to current // value of our cgfxShader node's "shader" attribute. if (!fFxFile && pNode) fNewFxFile = pNode->shaderFxFile(); // If user didn't specify technique name, default to current // value of our cgfxShader node's "technique" attribute. // // If a new fx file has been specified without a technique, we // leave the technique name empty so that the first technique of // the effect will be selected. if (!fTechnique && pNode) fNewTechnique = pNode->getTechnique(); // If user didn't specify profile name, default to current // value of our cgfxShader node's "profile" attribute. if (!fProfile && pNode) fNewProfile = pNode->getProfile(); // // Load the effect from the .fx file. // if (fFxFile) { // Attempt to read the new fEffect from the file // MString file = cgfxFindFile(fNewFxFile); MString projectFile = cgfxFindFile(fNewFxFile, true); // Compile and create the effect. fNewEffect = cgfxEffect::loadEffect(file, cgfxProfile::getProfile(fNewProfile)); //// Set the device. if (fNewEffect->isValid()) { // There is no current view in batch mode, just return // success then const MGlobal::MMayaState mayaState = MGlobal::mayaState(&status); if ( !status ) return status; if ( mayaState == MGlobal::kBatch ) return MS::kSuccess; fNewFxFile = projectFile; M3dView view = M3dView::active3dView(); // The M3dView class doesn't return the correct status if // there isn't an active 3D view, so we rely on the // success of beginGL() which will make the context // current. // if (!view.beginGL()) { MString es = "There is no active view to bind " + sWho + " to."; MGlobal::displayWarning( es ); return MS::kSuccess; } view.endGL(); } // Tell user if successful. if (fNewEffect->isValid()) { sFeedback = sWho; sFeedback += " loaded effect \""; sFeedback += file; sFeedback += "\""; MGlobal::displayInfo( sFeedback ); } else { sFeedback = sWho; sFeedback += " unable to load effect \""; sFeedback += file.length() ? file : fNewFxFile; sFeedback += "\""; MGlobal::displayError( sFeedback ); return MS::kFailure; } } // Create an MDGModifier to hold an agenda of operations to be // performed to update the DG. We build the agenda here; // then invoke it to do/redo/undo the updates. fDagMod = new MDGModifier; // Create new cgfxShader node if requested. if ( !fIsEdit ) { // Create node. oNode = fDagMod->createNode(cgfxShaderNode::sId, &status); M_CHECK( status ); if ( fNodeName.length() > 0 ) { status = fDagMod->renameNode(oNode, fNodeName); M_CHECK( status ); } status = fnNode.setObject( oNode ); M_CHECK( status && fnNode.typeId() == cgfxShaderNode::sId ); pNode = (cgfxShaderNode*)fnNode.userNode(); M_CHECK( pNode ); // On successful completion, redoCmd() will select the new node. // Save old selection for undo. status = MGlobal::getActiveSelectionList( fOldSelection ); M_CHECK( status ); } if (fFxFile) { // Save the current state of the node for undo purposes fOldFxFile = pNode->shaderFxFile(); fOldEffect = pNode->effect(); // save old CGeffect cgfxShaderNode::NodeList nodes; // getNodesToUpdate will return the list of nodes that will need to be updated : // if the new fx file is the same as the old fx file, the action is considered a reload, // we'll gather all the nodes that are using the old effect and reload them all. // else the effect file is different and only the current node will be updated. getNodesToUpdate(fOldEffect, pNode, nodes); cgfxShaderNode::NodeList::const_iterator it = nodes.begin(); cgfxShaderNode::NodeList::const_iterator itEnd = nodes.end(); for(; it != itEnd; ++it) { cgfxShaderNode* node = *it; MStringArray &oldAttributeList = fOldAttributeList[node]; cgfxRCPtr<cgfxAttrDefList> &oldAttrDefList = fOldAttrDefList[node]; MStringArray &newAttributeList = fNewAttributeList[node]; cgfxRCPtr<cgfxAttrDefList> &newAttrDefList = fNewAttrDefList[node]; node->getAttributeList( oldAttributeList ); oldAttrDefList = node->attrDefList(); // save old cgfxAttrDefList ptr // Now figure out what to do with the node. // // updateNode does a fair amount of work. First, it gets the // cgfxAttrDefList from the effect. Then it gets the equivalent // list from the node itself. It determines which attributes need // to be added and which need to be deleted and fills in all the // changes in the MDagModifier fDagMod. Then it builds a new value // for the attributeList attribute. Finally, it builds a new // value for the attrDefList internal value. All these values are // returned here where we can set them into the node. // cgfxAttrDef::updateNode( fNewEffect, // IN node, // IN fDagMod, // UPD newAttrDefList, // OUT newAttributeList ); // OUT } } // Save a reference to the node in a selection list for undo/redo. status = fNodeSelection.add( oNode ); M_CHECK( status ); // Save the current state of the node for undo purposes fOldTechnique = pNode->getTechnique(); fOldProfile = pNode->getProfile(); // I think we have all the information to redoIt(). // // Typically, the doIt() method only collects the infomation required // to do/undo the action and then stores it in class members. The // redo method is then called to do the actuall work. This prevents // code duplication. // return redoCmd( oNode, fnNode, pNode ); } // cgfxShaderCmd::doCmd
void DMPDSExporter::fillBones( DMPSkeletonData::SubSkeletonStruct* subSkel, string parent, DMPParameters* param, MDagPath& jointDag ) { MStatus status; if (jointDag.apiType() != MFn::kJoint) { return; // early out. } DMPSkeletonData::BoneStruct newBone; newBone.boneHandle = (unsigned int)subSkel->bones.size(); newBone.name = jointDag.partialPathName().asUTF8(); newBone.parentName = parent; MFnIkJoint fnJoint(jointDag, &status); // matrix = [S] * [RO] * [R] * [JO] * [IS] * [T] /* These matrices are defined as follows: •[S] : scale •[RO] : rotateOrient (attribute name is rotateAxis) •[R] : rotate •[JO] : jointOrient •[IS] : parentScaleInverse •[T] : translate The methods to get the value of these matrices are: •[S] : getScale •[RO] : getScaleOrientation •[R] : getRotation •[JO] : getOrientation •[IS] : (the inverse of the getScale on the parent transformation matrix) •[T] : translation */ MVector trans = fnJoint.getTranslation(MSpace::kTransform); double scale[3]; fnJoint.getScale(scale); MQuaternion R, RO, JO; fnJoint.getScaleOrientation(RO); fnJoint.getRotation(R); fnJoint.getOrientation(JO); MQuaternion rot = RO * R * JO; newBone.translate[0] = trans.x * param->lum; newBone.translate[1] = trans.y * param->lum; newBone.translate[2] = trans.z * param->lum; newBone.orientation[0] = rot.w; newBone.orientation[1] = rot.x; newBone.orientation[2] = rot.y; newBone.orientation[3] = rot.z; newBone.scale[0] = scale[0]; newBone.scale[1] = scale[1]; newBone.scale[2] = scale[2]; subSkel->bones.push_back(newBone); // Load child joints for (unsigned int i=0; i<jointDag.childCount();i++) { MObject child; child = jointDag.child(i); MDagPath childDag = jointDag; childDag.push(child); fillBones(subSkel, newBone.name, param, childDag); } // now go for animations if (param->bExportSkelAnimation) { for (unsigned int i = 0; i < subSkel->animations.size(); ++i) { DMPSkeletonData::TransformAnimation& anim = subSkel->animations[i]; DMPSkeletonData::TransformTrack subTrack; subTrack.targetBone = newBone.name; MPlug plugT; // translate MPlug plugR; // R MPlug plugRO; // RO MPlug plugJO; // JO MPlug plugS; // scale double dataT[3]; double dataR[3]; double dataRO[3]; double dataJO[3]; double dataS[3]; MFnDependencyNode fnDependNode( jointDag.node(), &status ); plugT = fnDependNode.findPlug("translate", false, &status); plugR = fnDependNode.findPlug("rotate", false, &status); plugRO = fnDependNode.findPlug("rotateAxis", false, &status); plugJO = fnDependNode.findPlug("jointOrient", false, &status); plugS = fnDependNode.findPlug("scale", false, &status); float timeStep = param->samplerRate; if (param->animSampleType == DMPParameters::AST_Frame) { timeStep /= param->fps; } for (float curTime = anim.startTime; curTime <= anim.endTime; curTime += timeStep) { MTime mayaTime; DMPSkeletonData::TransformKeyFrame keyframe; keyframe.time = curTime - anim.startTime; mayaTime.setUnit(MTime::kSeconds); mayaTime.setValue(curTime); // Get its value at the specified Time. plugT.child(0).getValue(dataT[0], MDGContext(mayaTime)); plugT.child(1).getValue(dataT[1], MDGContext(mayaTime)); plugT.child(2).getValue(dataT[2], MDGContext(mayaTime)); plugR.child(0).getValue(dataR[0], MDGContext(mayaTime)); plugR.child(1).getValue(dataR[1], MDGContext(mayaTime)); plugR.child(2).getValue(dataR[2], MDGContext(mayaTime)); plugRO.child(0).getValue(dataRO[0], MDGContext(mayaTime)); plugRO.child(1).getValue(dataRO[1], MDGContext(mayaTime)); plugRO.child(2).getValue(dataRO[2], MDGContext(mayaTime)); plugJO.child(0).getValue(dataJO[0], MDGContext(mayaTime)); plugJO.child(1).getValue(dataJO[1], MDGContext(mayaTime)); plugJO.child(2).getValue(dataJO[2], MDGContext(mayaTime)); plugS.child(0).getValue(dataS[0], MDGContext(mayaTime)); plugS.child(1).getValue(dataS[1], MDGContext(mayaTime)); plugS.child(2).getValue(dataS[2], MDGContext(mayaTime)); // fill the frame. keyframe.translate[0] = dataT[0] * param->lum; keyframe.translate[1] = dataT[1] * param->lum; keyframe.translate[2] = dataT[2] * param->lum; // calculate quaternion. MEulerRotation rotR(dataR[0], dataR[1], dataR[2]); MEulerRotation rotRO(dataRO[0], dataRO[1], dataRO[2]); MEulerRotation rotJO(dataJO[0], dataJO[1], dataJO[2]); MQuaternion finalRot = rotRO.asQuaternion()*rotR.asQuaternion()*rotJO.asQuaternion(); keyframe.orientation[0] = finalRot.w; keyframe.orientation[1] = finalRot.x; keyframe.orientation[2] = finalRot.y; keyframe.orientation[3] = finalRot.z; keyframe.scale[0] = dataS[0]; keyframe.scale[1] = dataS[1]; keyframe.scale[2] = dataS[2]; subTrack.frames.push_back(keyframe); } anim.tracks.push_back(subTrack); } } }
bool atomExport::setUpAnimLayers(MSelectionList &sList,atomAnimLayers &animLayers, std::vector<atomNodeWithAnimLayers *> &nodesWithAnimLayers, std::set<std::string> &attrStrings, atomTemplateReader &templateReader) { unsigned int numObjects = sList.length(); nodesWithAnimLayers.resize(numObjects); bool somethingIsAnimLayered = false; for (unsigned int i = 0; i < numObjects; i++) { atomNodeWithAnimLayers *nodeWithLayer = NULL; //make sure it's a NULL, and preset it in case we skip this node nodesWithAnimLayers[i] = nodeWithLayer; MDagPath path; MObject node; if (sList.getDagPath (i, path) == MS::kSuccess) { MString name = path.partialPathName(); //if the name is in the template, only then write it out... if(templateReader.findNode(name)== false) { continue; } node = path.node(); } else if (sList.getDependNode (i, node) == MS::kSuccess) { if (!node.hasFn (MFn::kDependencyNode)) { continue; } MFnDependencyNode fnNode (node); MString name = fnNode.name(); if(templateReader.findNode(name)== false) { continue; } } if(node.isNull()==false) { MSelectionList localList; localList.add(node); MPlugArray animatablePlugs; MAnimUtil::findAnimatablePlugs(localList,animatablePlugs); unsigned int numPlugs = animatablePlugs.length(); MPlugArray cachedPlugs; for (unsigned int k = 0; k < numPlugs; k++) { MPlug plug = animatablePlugs[k]; MObjectArray layers; MPlugArray plugs; if(MAnimUtil::findAnimationLayers(plug,layers,plugs) && layers.length() > 0) { bool layerAdded = animLayers.addAnimLayers(layers); if(layerAdded) { if(nodeWithLayer == NULL) nodeWithLayer = new atomNodeWithAnimLayers(); nodeWithLayer->addPlugWithLayer(plug,layers,plugs); } somethingIsAnimLayered = somethingIsAnimLayered == false ? layerAdded : true; } } nodesWithAnimLayers[i] = nodeWithLayer; } } return somethingIsAnimLayered; }
bool usdWriteJob::beginJob(const std::string &iFileName, bool append, double startTime, double endTime) { // Check for DAG nodes that are a child of an already specified DAG node to export // if that's the case, report the issue and skip the export PxrUsdMayaUtil::ShapeSet::const_iterator m, n; PxrUsdMayaUtil::ShapeSet::const_iterator endPath = mArgs.dagPaths.end(); for (m = mArgs.dagPaths.begin(); m != endPath; ) { MDagPath path1 = *m; m++; for (n = m; n != endPath; n++) { MDagPath path2 = *n; if (PxrUsdMayaUtil::isAncestorDescendentRelationship(path1,path2)) { MString errorMsg = path1.fullPathName(); errorMsg += " and "; errorMsg += path2.fullPathName(); errorMsg += " have an ancestor relationship. Skipping USD Export."; MGlobal::displayError(errorMsg); return false; } } // for n } // for m // Make sure the file name is a valid one with a proper USD extension. const std::string iFileExtension = TfStringGetSuffix(iFileName, '.'); if (iFileExtension == PxrUsdMayaTranslatorTokens->UsdFileExtensionDefault || iFileExtension == PxrUsdMayaTranslatorTokens->UsdFileExtensionASCII || iFileExtension == PxrUsdMayaTranslatorTokens->UsdFileExtensionCrate) { mFileName = iFileName; } else { mFileName = TfStringPrintf("%s.%s", iFileName.c_str(), PxrUsdMayaTranslatorTokens->UsdFileExtensionDefault.GetText()); } MGlobal::displayInfo("usdWriteJob::beginJob: Create stage file "+MString(mFileName.c_str())); ArResolverContext resolverCtx = ArGetResolver().GetCurrentContext(); if (append) { mStage = UsdStage::Open(SdfLayer::FindOrOpen(mFileName), resolverCtx); if (!mStage) { MGlobal::displayError("Failed to open stage file "+MString(mFileName.c_str())); return false; } } else { mStage = UsdStage::CreateNew(mFileName, resolverCtx); if (!mStage) { MGlobal::displayError("Failed to create stage file "+MString(mFileName.c_str())); return false; } } // Set time range for the USD file mStage->SetStartTimeCode(startTime); mStage->SetEndTimeCode(endTime); mModelKindWriter.Reset(); // Setup the requested render layer mode: // defaultLayer - Switch to the default render layer before exporting, // then switch back afterwards (no layer switching if // the current layer IS the default layer). // currentLayer - No layer switching before or after exporting. Just // use whatever is the current render layer for export. // modelingVariant - Switch to the default render layer before exporting, // and export each render layer in the scene as a // modeling variant, then switch back afterwards (no // layer switching if the current layer IS the default // layer). The default layer will be made the default // modeling variant. MFnRenderLayer currentLayer(MFnRenderLayer::currentLayer()); mCurrentRenderLayerName = currentLayer.name(); if (mArgs.renderLayerMode == PxUsdExportJobArgsTokens->modelingVariant) { // Handle usdModelRootOverridePath for USD Variants MFnRenderLayer::listAllRenderLayers(mRenderLayerObjs); if (mRenderLayerObjs.length() > 1) { mArgs.usdModelRootOverridePath = SdfPath("/_BaseModel_"); } } // Switch to the default render layer unless the renderLayerMode is // 'currentLayer', or the default layer is already the current layer. if (mArgs.renderLayerMode != PxUsdExportJobArgsTokens->currentLayer && MFnRenderLayer::currentLayer() != MFnRenderLayer::defaultRenderLayer()) { // Set the RenderLayer to the default render layer MFnRenderLayer defaultLayer(MFnRenderLayer::defaultRenderLayer()); MGlobal::executeCommand(MString("editRenderLayerGlobals -currentRenderLayer ")+ defaultLayer.name(), false, false); } // Pre-process the argument dagPath path names into two sets. One set // contains just the arg dagPaths, and the other contains all parents of // arg dagPaths all the way up to the world root. Partial path names are // enough because Maya guarantees them to still be unique, and they require // less work to hash and compare than full path names. TfHashSet<std::string, TfHash> argDagPaths; TfHashSet<std::string, TfHash> argDagPathParents; PxrUsdMayaUtil::ShapeSet::const_iterator end = mArgs.dagPaths.end(); for (PxrUsdMayaUtil::ShapeSet::const_iterator it = mArgs.dagPaths.begin(); it != end; ++it) { MDagPath curDagPath = *it; std::string curDagPathStr(curDagPath.partialPathName().asChar()); argDagPaths.insert(curDagPathStr); while (curDagPath.pop() && curDagPath.length() >= 0) { curDagPathStr = curDagPath.partialPathName().asChar(); if (argDagPathParents.find(curDagPathStr) != argDagPathParents.end()) { // We've already traversed up from this path. break; } argDagPathParents.insert(curDagPathStr); } } // Now do a depth-first traversal of the Maya DAG from the world root. // We keep a reference to arg dagPaths as we encounter them. MDagPath curLeafDagPath; for (MItDag itDag(MItDag::kDepthFirst, MFn::kInvalid); !itDag.isDone(); itDag.next()) { MDagPath curDagPath; itDag.getPath(curDagPath); std::string curDagPathStr(curDagPath.partialPathName().asChar()); if (argDagPathParents.find(curDagPathStr) != argDagPathParents.end()) { // This dagPath is a parent of one of the arg dagPaths. It should // be included in the export, but not necessarily all of its // children should be, so we continue to traverse down. } else if (argDagPaths.find(curDagPathStr) != argDagPaths.end()) { // This dagPath IS one of the arg dagPaths. It AND all of its // children should be included in the export. curLeafDagPath = curDagPath; } else if (!MFnDagNode(curDagPath).hasParent(curLeafDagPath.node())) { // This dagPath is not a child of one of the arg dagPaths, so prune // it and everything below it from the traversal. itDag.prune(); continue; } MayaPrimWriterPtr primWriter = nullptr; if (!createPrimWriter(curDagPath, &primWriter) && curDagPath.length() > 0) { // This dagPath and all of its children should be pruned. itDag.prune(); continue; } if (primWriter) { mMayaPrimWriterList.push_back(primWriter); // Write out data (non-animated/default values). if (UsdPrim usdPrim = primWriter->write(UsdTimeCode::Default())) { MDagPath dag = primWriter->getDagPath(); mDagPathToUsdPathMap[dag] = usdPrim.GetPath(); // If we are merging transforms and the object derives from // MayaTransformWriter but isn't actually a transform node, we // need to add its parent. if (mArgs.mergeTransformAndShape) { MayaTransformWriterPtr xformWriter = boost::dynamic_pointer_cast<MayaTransformWriter>( primWriter); if (xformWriter) { MDagPath xformDag = xformWriter->getTransformDagPath(); mDagPathToUsdPathMap[xformDag] = usdPrim.GetPath(); } } mModelKindWriter.OnWritePrim(usdPrim, primWriter); if (primWriter->shouldPruneChildren()) { itDag.prune(); } } } } // Writing Materials/Shading PxrUsdMayaTranslatorMaterial::ExportShadingEngines( mStage, mArgs.dagPaths, mArgs.shadingMode, mArgs.mergeTransformAndShape, mArgs.usdModelRootOverridePath); if (!mModelKindWriter.MakeModelHierarchy(mStage)) { return false; } // now we populate the chasers and run export default mChasers.clear(); PxrUsdMayaChaserRegistry::FactoryContext ctx(mStage, mDagPathToUsdPathMap, mArgs); for (const std::string& chaserName : mArgs.chaserNames) { if (PxrUsdMayaChaserRefPtr fn = PxrUsdMayaChaserRegistry::GetInstance().Create(chaserName, ctx)) { mChasers.push_back(fn); } else { std::string error = TfStringPrintf("Failed to create chaser: %s", chaserName.c_str()); MGlobal::displayError(MString(error.c_str())); } } for (const PxrUsdMayaChaserRefPtr& chaser : mChasers) { if (!chaser->ExportDefault()) { return false; } } return true; }
String DocumentExporter::dagPathToColladaSid(const MDagPath & dagPath) { return mayaNameToColladaName(dagPath.partialPathName()); }
//----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- MSelectionList CVsSkinnerCmd::DoNewVolumes( const MDagPath &skinnerPath, const MSelectionList &skeletonList ) { MSelectionList retList; const bool optSelected( m_undo.ArgDatabase().isFlagSet( kOptSelected ) ); MSelectionList optSelection; m_undo.ArgDatabase().getObjects( optSelection ); // TODO: Maybe some fancier logic to only create volumes on joints that make sense? // Perhaps the ol' has children but no shapes gag? Watch out for vstHelperBones! MDagPath mDagPath; for ( MItSelectionList sIt( optSelection ); !sIt.isDone(); sIt.next() ) { if ( sIt.itemType() == MItSelectionList::kDagSelectionItem && sIt.getDagPath( mDagPath ) && mDagPath.hasFn( MFn::kTransform ) ) { if ( optSelected ) { MObject cObj( DoNewVolume( skinnerPath, mDagPath ) ); if ( cObj.isNull() ) { mwarn << "Couldn't create new volume on " << skinnerPath.partialPathName() << " using " << mDagPath.partialPathName() << " as a parent" << std::endl; } else { retList.add( skinnerPath, cObj, true ); } } else { MItDag dIt; for ( dIt.reset( mDagPath ); !dIt.isDone(); dIt.next() ) { dIt.getPath( mDagPath ); if ( mDagPath.childCount() ) { uint nShapes( 0 ); mDagPath.numberOfShapesDirectlyBelow( nShapes ); if ( nShapes == 0U || mDagPath.hasFn( MFn::kJoint ) ) { MObject cObj( DoNewVolume( skinnerPath, mDagPath ) ); if ( cObj.isNull() ) { mwarn << "Couldn't create new volume on " << skinnerPath.partialPathName() << " using " << mDagPath.partialPathName() << " as a parent" << std::endl; } else { retList.add( skinnerPath, cObj, true ); } } } } } } } return retList; }
bool atomExport::setUpCache(MSelectionList &sList, std::vector<atomCachedPlugs *> &cachedPlugs,atomAnimLayers &animLayers, bool sdk, bool constraint, bool layers, std::set<std::string> &attrStrings, atomTemplateReader &templateReader, MTime &startTime, MTime &endTime, MAngle::Unit angularUnit, MDistance::Unit linearUnit) { if(endTime<startTime) return false; //should never happen but just in case. unsigned int numObjects = sList.length(); cachedPlugs.resize(numObjects); double dStart = startTime.value(); double dEnd = endTime.value() + (.0000001); //little nudge in case of round off errors MTime::Unit unit = startTime.unit(); double tickStep = MTime(1.0,unit).value(); unsigned int numItems = ((unsigned int)((dEnd - dStart)/tickStep)) + 1; bool somethingIsCached = false; //if nothing get's cached no reason to run computation loop for (unsigned int i = 0; i < numObjects; i++) { atomCachedPlugs *plug = NULL; //make sure it's a NULL, and preset it in case we skip this node cachedPlugs[i] = plug; MDagPath path; MObject node; MString name; if (sList.getDagPath (i, path) == MS::kSuccess) { node = path.node(); name = path.partialPathName(); } else if (sList.getDependNode (i, node) == MS::kSuccess) { if (!node.hasFn (MFn::kDependencyNode)) { continue; } MFnDependencyNode fnNode (node); name = fnNode.name(); } if(node.isNull()==false) { if(i< animLayers.length()) { MPlugArray plugs; animLayers.getPlugs(i,plugs); std::set<std::string> tempAttrStrings; atomTemplateReader tempTemplateReader; plug = new atomCachedPlugs(name,node,plugs,sdk,constraint,layers, tempAttrStrings,tempTemplateReader,numItems,angularUnit, linearUnit); if(plug->hasCached() ==false) delete plug; else { cachedPlugs[i] = plug; somethingIsCached = true; } } else { if(templateReader.findNode(name)== false) { continue; } MSelectionList localList; localList.add(node); MPlugArray animatablePlugs; MAnimUtil::findAnimatablePlugs(localList,animatablePlugs); plug = new atomCachedPlugs(name,node,animatablePlugs,sdk,constraint,layers,attrStrings,templateReader,numItems,angularUnit, linearUnit); if(plug->hasCached() ==false) delete plug; else { cachedPlugs[i] = plug; somethingIsCached = true; } } } } bool computationFinished = true; //if no interrupt happens we will finish the computation if(somethingIsCached) { bool hasActiveProgress = false; if (MProgressWindow::reserve()) { hasActiveProgress = true; MProgressWindow::setInterruptable(true); MProgressWindow::startProgress(); MProgressWindow::setProgressRange(0, numObjects); MProgressWindow::setProgress(0); MStatus stringStat; MString msg = MStringResource::getString(kBakingProgress, stringStat); if(stringStat == MS::kSuccess) MProgressWindow::setTitle(msg); } unsigned int count =0; for(double tick = dStart; tick <= dEnd; tick += tickStep) { if(hasActiveProgress) MProgressWindow::setProgress(count); MTime time(tick,unit); MDGContext ctx(time); for(unsigned int z = 0; z< cachedPlugs.size(); ++z) { if(cachedPlugs[z]) cachedPlugs[z]->calculateValue(ctx,count); } if (hasActiveProgress && MProgressWindow::isCancelled()) { computationFinished = false; break; } ++count; } if(hasActiveProgress) MProgressWindow::endProgress(); } return computationFinished; }
//----------------------------------------------------------------------------- // Creates a vstAttachment Locator //----------------------------------------------------------------------------- MStatus CVstAttachmentCmd::DoCreate() { MDagModifier *mDagModifier( new MDagModifier ); if ( !mDagModifier ) { merr << "Can't create new MDagModifier" << std::endl; return MS::kFailure; } MString optName( "vstAttachment" ); if ( m_mArgDatabase->isFlagSet( kOptName ) ) { m_mArgDatabase->getFlagArgument( kOptName, 0, optName ); } // Create the helper bone locator's transform MObject xObj = mDagModifier->createNode( "transform" ); mDagModifier->doIt(); if ( xObj.isNull() ) { merr << "Can't create new transform node" << std::endl; return MS::kFailure; } // name the shape & the transform the same thing mDagModifier->renameNode( xObj, optName ); mDagModifier->doIt(); MObject vstAttachmentObj = mDagModifier->createNode( "vstAttachment", xObj ); if ( vstAttachmentObj.isNull() ) { merr << "Can't create new vstAttachment node" << std::endl; mDagModifier->undoIt(); return MS::kFailure; } // name the shape & the transform the same thing mDagModifier->renameNode( vstAttachmentObj, MFnDependencyNode( xObj ).name() ); mDagModifier->doIt(); m_undoable = true; m_mDagModifier = mDagModifier; if ( m_mArgDatabase->isFlagSet( kOptParent ) ) { MSelectionList mSelectionList; m_mArgDatabase->getObjects( mSelectionList ); for ( MItSelectionList sIt( mSelectionList, MFn::kDagNode ); !sIt.isDone(); sIt.next() ) { MDagPath mDagPath; if ( sIt.getDagPath( mDagPath ) ) { m_mDagModifier->reparentNode( xObj, mDagPath.node() ); m_mDagModifier->doIt(); break; } } } // Save the current selection just in case we want to undo stuff MGlobal::getActiveSelectionList( m_mSelectionList ); MDagPath xDagPath; MDagPath::getAPathTo( xObj, xDagPath ); MGlobal::select( xDagPath, MObject::kNullObj, MGlobal::kReplaceList ); setResult( xDagPath.partialPathName() ); return MS::kSuccess; }
MStatus atomExport::exportSelected( ofstream &animFile, MString ©Flags, std::set<std::string> &attrStrings, bool includeChildren, bool useSpecifiedTimes, MTime &startTime, MTime &endTime, bool statics, bool cached, bool sdk, bool constraint, bool layers, const MString& exportEditsFile, atomTemplateReader &templateReader) { MStatus status = MS::kFailure; // If the selection list is empty, then there are no anim curves // to export. // MSelectionList sList; std::vector<unsigned int> depths; SelectionGetter::getSelectedObjects(includeChildren,sList,depths); if (sList.isEmpty()) { MString msg = MStringResource::getString(kNothingSelected, status); MGlobal::displayError(msg); return (MS::kFailure); } // Copy any anim curves to the API clipboard. // MString command(copyFlags); // Always write out header if (!fWriter.writeHeader(animFile,useSpecifiedTimes, startTime,endTime)) { return (MS::kFailure); } atomAnimLayers animLayers; std::vector<atomNodeWithAnimLayers *> nodesWithAnimLayers; if(layers) { bool hasAnimLayers = animLayers.getOrderedAnimLayers(); //any layers in the scene? hasAnimLayers = setUpAnimLayers(sList,animLayers, nodesWithAnimLayers,attrStrings,templateReader); //any layers on our selection? if(hasAnimLayers) { //add the layers to the sList... unsigned int oldLength = sList.length(); animLayers.addLayersToStartOfSelectionList(sList); unsigned int diffLength = sList.length() - oldLength; atomNodeWithAnimLayers * nullPad = NULL; for(unsigned int k =0 ;k < diffLength;++k) //need to pad the beginning of the nodesWithAnimlayers with any layer that was added { nodesWithAnimLayers.insert(nodesWithAnimLayers.begin(),nullPad); depths.insert(depths.begin(),0); } } } //if caching is on, we pre iterate through the objects, find //each plug that's cached and then cache the data all at once std::vector<atomCachedPlugs *> cachedPlugs; if(cached) { bool passed = setUpCache(sList,cachedPlugs,animLayers,sdk, constraint, layers, attrStrings,templateReader,startTime, endTime, fWriter.getAngularUnit(), fWriter.getLinearUnit()); //this sets it up and runs the cache; if(passed == false) //failed for some reason, one reason is that the user canceled the computation { //first delete everything though //delete any cachedPlugs objects that we created. for(unsigned int z = 0; z< cachedPlugs.size(); ++z) { if(cachedPlugs[z]) delete cachedPlugs[z]; } //and delete any any layers too for(unsigned int zz = 0; zz< nodesWithAnimLayers.size(); ++zz) { if(nodesWithAnimLayers[zz]) delete nodesWithAnimLayers[zz]; } MString msg = MStringResource::getString(kCachingCanceled, status); MGlobal::displayError(msg); return (MS::kFailure); } } unsigned int numObjects = sList.length(); bool computationFinished = true; //not sure if in a headless mode we may want to not show the progress, should //still run if that's the case bool hasActiveProgress = false; if (MProgressWindow::reserve()) { hasActiveProgress = true; MProgressWindow::setInterruptable(true); MProgressWindow::startProgress(); MProgressWindow::setProgressRange(0, numObjects); MProgressWindow::setProgress(0); MStatus stringStat; MString msg = MStringResource::getString(kExportProgress, stringStat); if(stringStat == MS::kSuccess) MProgressWindow::setTitle(msg); } if (exportEditsFile.length() > 0) { fWriter.writeExportEditsFilePresent(animFile); } if(layers) { animLayers.writeAnimLayers(animFile,fWriter); } bool haveAnyAnimatableStuff = false; //will remain false if no curves or statics for (unsigned int i = 0; i < numObjects; i++) { if(hasActiveProgress) MProgressWindow::setProgress(i); MString localCommand; bool haveAnimatedCurves = false; //local flag, if true this node has animated curves bool haveAnimatableChannels = false; //local flag, if true node has some animatable statics MDagPath path; MObject node; if (sList.getDagPath (i, path) == MS::kSuccess) { MString name = path.partialPathName(); //if the name is in the template, only then write it out... if(templateReader.findNode(name)== false) continue; //we use this to both write out the cached plugs for this node but for also to not write out //the plugs which are cached when writing anim curves. atomCachedPlugs * cachedPlug = NULL; if(cached && i < cachedPlugs.size()) cachedPlug = cachedPlugs[i]; atomNodeWithAnimLayers *layerPlug = NULL; if(layers && i < nodesWithAnimLayers.size()) layerPlug = nodesWithAnimLayers[i]; unsigned int depth = depths[i]; unsigned int childCount = path.childCount(); MObject object = path.node(); atomNodeNameReplacer::NodeType nodeType = (object.hasFn(MFn::kShape)) ? atomNodeNameReplacer::eShape : atomNodeNameReplacer::eDag; fWriter.writeNodeStart(animFile,nodeType,name,depth,childCount); MPlugArray animatablePlugs; MSelectionList localList; localList.add(object); MAnimUtil::findAnimatablePlugs(localList,animatablePlugs); if(writeAnimCurves(animFile,name,cachedPlug, layerPlug, command, haveAnimatedCurves,templateReader) != MS::kSuccess ) { return (MS::kFailure); } else if(haveAnimatedCurves) { haveAnyAnimatableStuff = true; } if(statics||cached) { writeStaticAndCached (animatablePlugs,cachedPlug,statics,cached,animFile,attrStrings,name,depth,childCount, haveAnimatableChannels,templateReader); } fWriter.writeNodeEnd(animFile); } else if (sList.getDependNode (i, node) == MS::kSuccess) { if (!node.hasFn (MFn::kDependencyNode)) { return (MS::kFailure); } MPlugArray animatablePlugs; MFnDependencyNode fnNode (node, &status); MString name = fnNode.name(); atomNodeNameReplacer::NodeType nodeType = atomNodeNameReplacer::eDepend; atomNodeWithAnimLayers *layerPlug = NULL; //if a layer we get our own attrs if(i< animLayers.length()) { MPlugArray plugs; animLayers.getPlugs(i,animatablePlugs); nodeType = atomNodeNameReplacer::eAnimLayer; } else { if(templateReader.findNode(name)== false) { continue; } MSelectionList localList; localList.add(node); MAnimUtil::findAnimatablePlugs(localList,animatablePlugs); if(layers && i < nodesWithAnimLayers.size()) layerPlug = nodesWithAnimLayers[i]; } //we use this to both write out the cached plugs for this node but for also to not write out //the plugs which are cached when writing anim curves. atomCachedPlugs * cachedPlug = NULL; if(cached && i < cachedPlugs.size()) cachedPlug = cachedPlugs[i]; fWriter.writeNodeStart(animFile,nodeType,name); if(writeAnimCurves(animFile,name, cachedPlug,layerPlug,command, haveAnimatedCurves,templateReader) != MS::kSuccess ) { return (MS::kFailure); } else if(haveAnimatedCurves) { haveAnyAnimatableStuff = true; } if(statics||cached) { writeStaticAndCached (animatablePlugs,cachedPlug,statics,cached,animFile,attrStrings,name,0,0,haveAnimatableChannels,templateReader); } fWriter.writeNodeEnd(animFile); } if(haveAnimatableChannels==true) haveAnyAnimatableStuff = true; if (hasActiveProgress && MProgressWindow::isCancelled()) { computationFinished = false; break; } } if (exportEditsFile.length() > 0) { fWriter.writeExportEditsFile(animFile,exportEditsFile); } //delete any cachedPlugs objects that we created. for(unsigned int z = 0; z< cachedPlugs.size(); ++z) { if(cachedPlugs[z]) delete cachedPlugs[z]; } //and delete any any layers too for(unsigned int zz = 0; zz< nodesWithAnimLayers.size(); ++zz) { if(nodesWithAnimLayers[zz]) delete nodesWithAnimLayers[zz]; } if(computationFinished == false) //failed for some reason, one reason is that the user canceled the computation { MString msg = MStringResource::getString(kSavingCanceled, status); MGlobal::displayError(msg); return (MS::kFailure); } if(hasActiveProgress) MProgressWindow::endProgress(); if(haveAnyAnimatableStuff == false) { MString msg = MStringResource::getString(kAnimCurveNotFound, status); MGlobal::displayError(msg); return (MS::kFailure); } else return (MS::kSuccess); }
MStatus vxCache::doIt( const MArgList& args ) { MStatus status = parseArgs( args ); if( status != MS::kSuccess ) return status; MArgDatabase argData(syntax(), args); MAnimControl timeControl; MTime time = timeControl.currentTime(); int frame =int(time.value()); MString proj; MGlobal::executeCommand( MString ("string $p = `workspace -q -fn`"), proj ); MSelectionList selList; MGlobal::getActiveSelectionList ( selList ); MItSelectionList iter( selList ); MString cache_path = proj + "/data/"; MString cache_name; MString scene_name = "untitled"; worldSpace = false; if (argData.isFlagSet("-p")) argData.getFlagArgument("-p", 0, cache_path); if (argData.isFlagSet("-n")) argData.getFlagArgument("-n", 0, cache_name); if (argData.isFlagSet("-w")) argData.getFlagArgument("-w", 0, worldSpace); for ( ; !iter.isDone(); iter.next() ) { MDagPath meshPath; iter.getDagPath( meshPath ); meshPath.extendToShape(); MObject meshObj = meshPath.node(); MString surface = meshPath.partialPathName(); zWorks::validateFilePath(surface); char filename[512]; cache_name = surface; if(argData.isFlagSet("-sg")) sprintf( filename, "%s/%s.mcf", cache_path.asChar(), cache_name.asChar() ); else sprintf( filename, "%s/%s.%d.mcf", cache_path.asChar(), cache_name.asChar(), frame ); MDagPath surfDag; if ( meshPath.hasFn(MFn::kMesh)) { writeMesh(filename, meshPath, meshObj); MGlobal::displayInfo ( MString("vxCache writes ") + filename); } else MGlobal::displayError ( surface + "- Cannot find mesh to write!" ); } if ( selList.length() == 0 ) { MGlobal:: displayError ( "Nothing is selected!" ); return MS::kSuccess; } return MS::kSuccess; }