MStatus sgBDataCmd_key::startExport( MString pathFolder ) { MStatus status; m_filePaths.clear(); for( unsigned int i=0; i< m_pathArrExport.length(); i++ ) { MFnDagNode fnNode( m_pathArrExport[i], &status ); if( !status ) continue; MString targetName = fnNode.partialPathName(); targetName.substitute( ":", "_" ); targetName.substitute( "|", "_" ); m_filePaths.append( pathFolder + "\\" + targetName + ".sgKeyData" ); } m_objectKeyDatasExport.setLength( m_pathArrExport.length() ); for( unsigned int i=0; i< m_pathArrExport.length(); i++ ) { setObjectKeyDataDefault( m_objectKeyDatasExport[i], m_pathArrExport[i], m_exportByMatrix ); unsigned int unit = MTime().unit(); MString nameTarget = MFnDagNode( m_pathArrExport[i] ).fullPathName(); std::ofstream outFile( m_filePaths[i].asChar(), ios::binary ); writeString( nameTarget, outFile ); writeUnsignedInt( unit, outFile ); writeStringArray( m_objectKeyDatasExport[i].namesAttribute, outFile ); outFile.close(); } return MS::kSuccess; }
bool cStructLoader::CheckUnmodified(void) { time_t curr_mtime=MTime(false); if(mtime && mtime<curr_mtime && SL_TSTFLAG(SL_WATCH)) { PRINTF(L_CORE_LOAD,"abort save as file %s has been changed externaly",path); return false; } return true; }
MStatus sgBDataCmd_key::importData() { MStatus status; MTime::Unit currentUnit = MTime().unit(); MPlugArray connections; sgObject_keyData& objectKeyData = m_objectKeyDataImport; MObject& oTarget = objectKeyData.oTargetNode; MDoubleArray& dArrTime = objectKeyData.dArrTime; MTime::Unit unit = (MTime::Unit)objectKeyData.unit; MFnDagNode fnNode = oTarget; MPlugArray targetPlugs; unsigned int numAttr = objectKeyData.namesAttribute.length(); unsigned int lengthTime = dArrTime.length(); for( unsigned int j=0; j<numAttr; j++ ) { if( numAttr <= j ) break; MPlug targetPlug = fnNode.findPlug( objectKeyData.namesAttribute[j] ); targetPlug.connectedTo( connections, true, false ); if( connections.length() ){ m_dgMod_connection.disconnect( connections[0], targetPlug ); m_dgMod_delete.deleteNode( connections[0].node() ); } m_dgMod_connection.doIt(); m_dgMod_delete.doIt(); MObject oAnimCurve = MFnAnimCurve().create( targetPlug ); m_oArrKeyAfter.append( oAnimCurve ); MFnAnimCurve fnAnimCurve( oAnimCurve ); for( unsigned int k=0; k<lengthTime; k++ ) { double& dTime = dArrTime[k]; double& dValue = objectKeyData.dArrValuesArray[ k*numAttr+j ]; MTime mTime( dTime, unit ); mTime.setUnit( currentUnit ); fnAnimCurve.addKeyframe( mTime, dValue ); } } return MS::kSuccess; };
static bool _GetTimeAndValueArrayForUsdAttribute( const UsdAttribute& usdAttr, const GfInterval& timeInterval, MTimeArray* timeArray, MDoubleArray* valueArray, const MDistance::Unit convertToUnit = MDistance::kMillimeters) { static const TfType& floatType = TfType::Find<float>(); std::vector<double> timeSamples; if (!_CheckUsdTypeAndResizeArrays(usdAttr, floatType, timeInterval, &timeSamples, timeArray, valueArray)) { return false; } size_t numTimeSamples = timeSamples.size(); for (size_t i = 0; i < numTimeSamples; ++i) { const double timeSample = timeSamples[i]; float attrValue; if (!usdAttr.Get(&attrValue, timeSample)) { return false; } switch (convertToUnit) { case MDistance::kInches: attrValue = UsdMayaUtil::ConvertMMToInches(attrValue); break; case MDistance::kCentimeters: attrValue = UsdMayaUtil::ConvertMMToCM(attrValue); break; default: // The input is expected to be in millimeters. break; } timeArray->set(MTime(timeSample), i); valueArray->set(attrValue, i); } return true; }
void cStructLoader::Save(void) { if(CheckDoSave()) { cSafeFile f(path); if(f.Open()) { ListLock(false); for(cStructItem *it=First(); it; it=Next(it)) if(!it->Deleted() && !it->Save(f)) break; f.Close(); mtime=MTime(true); Modified(false); ListUnlock(); PRINTF(L_CORE_LOAD,"saved %s to %s",type,path); } } }
// Load a blend shape animation track Track BlendShape::loadTrack(float start,float stop,float rate,ParamList& params,int targetIndex,int startPoseId) { MStatus stat; MString msg; std::vector<float> times; // Create a track for current clip Track t; t.m_type = TT_POSE; t.m_target = m_target; t.m_index = targetIndex; t.m_vertexKeyframes.clear(); // Calculate times from clip sample rate times.clear(); if (rate <= 0) { std::cout << "invalid sample rate for the clip (must be >0), we skip it\n"; std::cout.flush(); return t; } for (float time=start; time<stop; time+=rate) times.push_back(time); times.push_back(stop); // Get animation length float length=0; if (times.size() >= 0) length = times[times.size()-1] - times[0]; if (length < 0) { std::cout << "invalid time range for the clip, we skip it\n"; std::cout.flush(); return t; } // Evaluate animation curves at selected times for (int i=0; i<times.size(); i++) { // Set time to wanted sample time MAnimControl::setCurrentTime(MTime(times[i],MTime::kSeconds)); // Load a keyframe at current time vertexKeyframe key = loadKeyframe(times[i]-times[0],params,targetIndex, startPoseId); // Add keyframe to joint track if (key.poserefs.size() > 0) t.addVertexKeyframe(key); } // Clip successfully loaded return t; }
static bool _GetTimeAndValueArrayForUsdAttribute( const UsdAttribute& usdAttr, const PxrUsdMayaPrimReaderArgs& args, MTimeArray* timeArray, MDoubleArray* valueArray, bool millimetersToInches=false) { static const TfType& floatType = TfType::Find<float>(); std::vector<double> timeSamples; if (!_CheckUsdTypeAndResizeArrays(usdAttr, floatType, args, &timeSamples, timeArray, valueArray)) { return false; } size_t numTimeSamples = timeSamples.size(); for (size_t i = 0; i < numTimeSamples; ++i) { const double timeSample = timeSamples[i]; float attrValue; if (!usdAttr.Get(&attrValue, timeSample)) { return false; } if (millimetersToInches) { attrValue = PxrUsdMayaUtil::ConvertMMToInches(attrValue); } timeArray->set(MTime(timeSample), i); valueArray->set(attrValue, i); } return true; }
// This is primarily intended for use in translating the clippingRange // USD attribute which is stored in USD as a single GfVec2f value but // in Maya as separate nearClipPlane and farClipPlane attributes. static bool _GetTimeAndValueArraysForUsdAttribute( const UsdAttribute& usdAttr, const GfInterval& timeInterval, MTimeArray* timeArray, MDoubleArray* valueArray1, MDoubleArray* valueArray2) { static const TfType& vec2fType = TfType::Find<GfVec2f>(); std::vector<double> timeSamples; if (!_CheckUsdTypeAndResizeArrays(usdAttr, vec2fType, timeInterval, &timeSamples, timeArray, valueArray1)) { return false; } size_t numTimeSamples = timeSamples.size(); valueArray2->setLength(numTimeSamples); for (size_t i = 0; i < numTimeSamples; ++i) { const double timeSample = timeSamples[i]; GfVec2f attrValue; if (!usdAttr.Get(&attrValue, timeSample)) { return false; } timeArray->set(MTime(timeSample), i); valueArray1->set(attrValue[0], i); valueArray2->set(attrValue[1], i); } return true; }
MStatus AlembicExportCommand::doIt(const MArgList &args) { ESS_PROFILE_SCOPE("AlembicExportCommand::doIt"); MStatus status = MS::kFailure; MTime currentAnimStartTime = MAnimControl::animationStartTime(), currentAnimEndTime = MAnimControl::animationEndTime(), oldCurTime = MAnimControl::currentTime(), curMinTime = MAnimControl::minTime(), curMaxTime = MAnimControl::maxTime(); MArgParser argData(syntax(), args, &status); if (argData.isFlagSet("help")) { // TODO: implement help for this command // MGlobal::displayInfo(util::getHelpText()); return MS::kSuccess; } unsigned int jobCount = argData.numberOfFlagUses("jobArg"); MStringArray jobStrings; if (jobCount == 0) { // TODO: display dialog MGlobal::displayError("[ExocortexAlembic] No jobs specified."); MPxCommand::setResult( "Error caught in AlembicExportCommand::doIt: no job specified"); return status; } else { // get all of the jobstrings for (unsigned int i = 0; i < jobCount; i++) { MArgList jobArgList; argData.getFlagArgumentList("jobArg", i, jobArgList); jobStrings.append(jobArgList.asString(0)); } } // create a vector to store the jobs std::vector<AlembicWriteJob *> jobPtrs; double minFrame = 1000000.0; double maxFrame = -1000000.0; double maxSteps = 1; double maxSubsteps = 1; // init the curve accumulators AlembicCurveAccumulator::Initialize(); try { // for each job, check the arguments bool failure = false; for (unsigned int i = 0; i < jobStrings.length(); ++i) { double frameIn = 1.0; double frameOut = 1.0; double frameSteps = 1.0; double frameSubSteps = 1.0; MString filename; bool purepointcache = false; bool normals = true; bool uvs = true; bool facesets = true; bool bindpose = true; bool dynamictopology = false; bool globalspace = false; bool withouthierarchy = false; bool transformcache = false; bool useInitShadGrp = false; bool useOgawa = false; // Later, will need to be changed! MStringArray objectStrings; std::vector<std::string> prefixFilters; std::set<std::string> attributes; std::vector<std::string> userPrefixFilters; std::set<std::string> userAttributes; MObjectArray objects; std::string search_str, replace_str; // process all tokens of the job MStringArray tokens; jobStrings[i].split(';', tokens); for (unsigned int j = 0; j < tokens.length(); j++) { MStringArray valuePair; tokens[j].split('=', valuePair); if (valuePair.length() != 2) { MGlobal::displayWarning( "[ExocortexAlembic] Skipping invalid token: " + tokens[j]); continue; } const MString &lowerValue = valuePair[0].toLowerCase(); if (lowerValue == "in") { frameIn = valuePair[1].asDouble(); } else if (lowerValue == "out") { frameOut = valuePair[1].asDouble(); } else if (lowerValue == "step") { frameSteps = valuePair[1].asDouble(); } else if (lowerValue == "substep") { frameSubSteps = valuePair[1].asDouble(); } else if (lowerValue == "normals") { normals = valuePair[1].asInt() != 0; } else if (lowerValue == "uvs") { uvs = valuePair[1].asInt() != 0; } else if (lowerValue == "facesets") { facesets = valuePair[1].asInt() != 0; } else if (lowerValue == "bindpose") { bindpose = valuePair[1].asInt() != 0; } else if (lowerValue == "purepointcache") { purepointcache = valuePair[1].asInt() != 0; } else if (lowerValue == "dynamictopology") { dynamictopology = valuePair[1].asInt() != 0; } else if (lowerValue == "globalspace") { globalspace = valuePair[1].asInt() != 0; } else if (lowerValue == "withouthierarchy") { withouthierarchy = valuePair[1].asInt() != 0; } else if (lowerValue == "transformcache") { transformcache = valuePair[1].asInt() != 0; } else if (lowerValue == "filename") { filename = valuePair[1]; } else if (lowerValue == "objects") { // try to find each object valuePair[1].split(',', objectStrings); } else if (lowerValue == "useinitshadgrp") { useInitShadGrp = valuePair[1].asInt() != 0; } // search/replace else if (lowerValue == "search") { search_str = valuePair[1].asChar(); } else if (lowerValue == "replace") { replace_str = valuePair[1].asChar(); } else if (lowerValue == "ogawa") { useOgawa = valuePair[1].asInt() != 0; } else if (lowerValue == "attrprefixes") { splitListArg(valuePair[1], prefixFilters); } else if (lowerValue == "attrs") { splitListArg(valuePair[1], attributes); } else if (lowerValue == "userattrprefixes") { splitListArg(valuePair[1], userPrefixFilters); } else if (lowerValue == "userattrs") { splitListArg(valuePair[1], userAttributes); } else { MGlobal::displayWarning( "[ExocortexAlembic] Skipping invalid token: " + tokens[j]); continue; } } // now check the object strings for (unsigned int k = 0; k < objectStrings.length(); k++) { MSelectionList sl; MString objectString = objectStrings[k]; sl.add(objectString); MDagPath dag; for (unsigned int l = 0; l < sl.length(); l++) { sl.getDagPath(l, dag); MObject objRef = dag.node(); if (objRef.isNull()) { MGlobal::displayWarning("[ExocortexAlembic] Skipping object '" + objectStrings[k] + "', not found."); break; } // get all parents MObjectArray parents; // check if this is a camera bool isCamera = false; for (unsigned int m = 0; m < dag.childCount(); ++m) { MFnDagNode child(dag.child(m)); MFn::Type ctype = child.object().apiType(); if (ctype == MFn::kCamera) { isCamera = true; break; } } if (dag.node().apiType() == MFn::kTransform && !isCamera && !globalspace && !withouthierarchy) { MDagPath ppath = dag; while (!ppath.node().isNull() && ppath.length() > 0 && ppath.isValid()) { parents.append(ppath.node()); if (ppath.pop() != MStatus::kSuccess) { break; } } } else { parents.append(dag.node()); } // push all parents in while (parents.length() > 0) { bool found = false; for (unsigned int m = 0; m < objects.length(); m++) { if (objects[m] == parents[parents.length() - 1]) { found = true; break; } } if (!found) { objects.append(parents[parents.length() - 1]); } parents.remove(parents.length() - 1); } // check all of the shapes below if (!transformcache) { sl.getDagPath(l, dag); for (unsigned int m = 0; m < dag.childCount(); m++) { MFnDagNode child(dag.child(m)); if (child.isIntermediateObject()) { continue; } objects.append(child.object()); } } } } // check if we have incompatible subframes if (maxSubsteps > 1.0 && frameSubSteps > 1.0) { const double part = (frameSubSteps > maxSubsteps) ? (frameSubSteps / maxSubsteps) : (maxSubsteps / frameSubSteps); if (abs(part - floor(part)) > 0.001) { MString frameSubStepsStr, maxSubstepsStr; frameSubStepsStr.set(frameSubSteps); maxSubstepsStr.set(maxSubsteps); MGlobal::displayError( "[ExocortexAlembic] You cannot combine substeps " + frameSubStepsStr + " and " + maxSubstepsStr + " in one export. Aborting."); return MStatus::kInvalidParameter; } } // remember the min and max values for the frames if (frameIn < minFrame) { minFrame = frameIn; } if (frameOut > maxFrame) { maxFrame = frameOut; } if (frameSteps > maxSteps) { maxSteps = frameSteps; } if (frameSteps > 1.0) { frameSubSteps = 1.0; } if (frameSubSteps > maxSubsteps) { maxSubsteps = frameSubSteps; } // check if we have a filename if (filename.length() == 0) { MGlobal::displayError("[ExocortexAlembic] No filename specified."); for (size_t k = 0; k < jobPtrs.size(); k++) { delete (jobPtrs[k]); } MPxCommand::setResult( "Error caught in AlembicExportCommand::doIt: no filename " "specified"); return MStatus::kFailure; } // construct the frames MDoubleArray frames; { const double frameIncr = frameSteps / frameSubSteps; for (double frame = frameIn; frame <= frameOut; frame += frameIncr) { frames.append(frame); } } AlembicWriteJob *job = new AlembicWriteJob(filename, objects, frames, useOgawa, prefixFilters, attributes, userPrefixFilters, userAttributes); job->SetOption("exportNormals", normals ? "1" : "0"); job->SetOption("exportUVs", uvs ? "1" : "0"); job->SetOption("exportFaceSets", facesets ? "1" : "0"); job->SetOption("exportInitShadGrp", useInitShadGrp ? "1" : "0"); job->SetOption("exportBindPose", bindpose ? "1" : "0"); job->SetOption("exportPurePointCache", purepointcache ? "1" : "0"); job->SetOption("exportDynamicTopology", dynamictopology ? "1" : "0"); job->SetOption("indexedNormals", "1"); job->SetOption("indexedUVs", "1"); job->SetOption("exportInGlobalSpace", globalspace ? "1" : "0"); job->SetOption("flattenHierarchy", withouthierarchy ? "1" : "0"); job->SetOption("transformCache", transformcache ? "1" : "0"); // check if the search/replace strings are valid! if (search_str.length() ? !replace_str.length() : replace_str.length()) // either search or // replace string is // missing or empty! { ESS_LOG_WARNING( "Missing search or replace parameter. No strings will be " "replaced."); job->replacer = SearchReplace::createReplacer(); } else { job->replacer = SearchReplace::createReplacer(search_str, replace_str); } // check if the job is satifsied if (job->PreProcess() != MStatus::kSuccess) { MGlobal::displayError("[ExocortexAlembic] Job skipped. Not satisfied."); delete (job); failure = true; break; } // push the job to our registry MGlobal::displayInfo("[ExocortexAlembic] Using WriteJob:" + jobStrings[i]); jobPtrs.push_back(job); } if (failure) { for (size_t k = 0; k < jobPtrs.size(); k++) { delete (jobPtrs[k]); } return MS::kFailure; } // compute the job count unsigned int jobFrameCount = 0; for (size_t i = 0; i < jobPtrs.size(); i++) jobFrameCount += (unsigned int)jobPtrs[i]->GetNbObjects() * (unsigned int)jobPtrs[i]->GetFrames().size(); // now, let's run through all frames, and process the jobs const double frameRate = MTime(1.0, MTime::kSeconds).as(MTime::uiUnit()); const double incrSteps = maxSteps / maxSubsteps; double nextFrame = minFrame + incrSteps; for (double frame = minFrame; frame <= maxFrame; frame += incrSteps, nextFrame += incrSteps) { MAnimControl::setCurrentTime(MTime(frame / frameRate, MTime::kSeconds)); MAnimControl::setAnimationEndTime( MTime(nextFrame / frameRate, MTime::kSeconds)); MAnimControl::playForward(); // this way, it forces Maya to play exactly // one frame! and particles are updated! AlembicCurveAccumulator::StartRecordingFrame(); for (size_t i = 0; i < jobPtrs.size(); i++) { MStatus status = jobPtrs[i]->Process(frame); if (status != MStatus::kSuccess) { MGlobal::displayError("[ExocortexAlembic] Job aborted :" + jobPtrs[i]->GetFileName()); for (size_t k = 0; k < jobPtrs.size(); k++) { delete (jobPtrs[k]); } restoreOldTime(currentAnimStartTime, currentAnimEndTime, oldCurTime, curMinTime, curMaxTime); return status; } } AlembicCurveAccumulator::StopRecordingFrame(); } } catch (...) { MGlobal::displayError( "[ExocortexAlembic] Jobs aborted, force closing all archives!"); for (std::vector<AlembicWriteJob *>::iterator beg = jobPtrs.begin(); beg != jobPtrs.end(); ++beg) { (*beg)->forceCloseArchive(); } restoreOldTime(currentAnimStartTime, currentAnimEndTime, oldCurTime, curMinTime, curMaxTime); MPxCommand::setResult("Error caught in AlembicExportCommand::doIt"); status = MS::kFailure; } MAnimControl::stop(); AlembicCurveAccumulator::Destroy(); // restore the animation start/end time and the current time! restoreOldTime(currentAnimStartTime, currentAnimEndTime, oldCurTime, curMinTime, curMaxTime); // delete all jobs for (size_t k = 0; k < jobPtrs.size(); k++) { delete (jobPtrs[k]); } // remove all known archives deleteAllArchives(); return status; }
MStatus AlembicWriteJob::PreProcess() { ESS_PROFILE_SCOPE("AlembicWriteJob::PreProcess"); // check filenames if (mFileName.length() == 0) { MGlobal::displayError("[ExocortexAlembic] No filename specified."); MPxCommand::setResult( "Error caught in AlembicWriteJob::PreProcess: no filename specified"); return MStatus::kInvalidParameter; } // check objects if (mSelection.length() == 0) { MGlobal::displayError("[ExocortexAlembic] No objects specified."); MPxCommand::setResult( "Error caught in AlembicWriteJob::PreProcess: no objects specified"); return MStatus::kInvalidParameter; } // check frames if (mFrames.size() == 0) { MGlobal::displayError("[ExocortexAlembic] No frames specified."); MPxCommand::setResult( "Error caught in AlembicWriteJob::PreProcess: no frame specified"); return MStatus::kInvalidParameter; } // check if the file is currently in use if (getRefArchive(mFileName) > 0) { MGlobal::displayError("[ExocortexAlembic] Error writing to file '" + mFileName + "'. File currently in use."); MPxCommand::setResult( "Error caught in AlembicWriteJob::PreProcess: no filename already in " "use"); return MStatus::kInvalidParameter; } // init archive (use a locally scoped archive) // TODO: determine how to access the current maya scene path // MString sceneFileName = "Exported from: // "+Application().GetActiveProject().GetActiveScene().GetParameterValue("FileName").GetAsText(); try { createArchive("Exported from Maya."); mTop = mArchive.getTop(); // get the frame rate mFrameRate = MTime(1.0, MTime::kSeconds).as(MTime::uiUnit()); const double timePerSample = 1.0 / mFrameRate; std::vector<AbcA::chrono_t> frames; for (LONG i = 0; i < mFrames.size(); i++) { frames.push_back(mFrames[i] * timePerSample); } // create the sampling if (frames.size() > 1) { const double timePerCycle = frames[frames.size() - 1] - frames[0]; AbcA::TimeSamplingType samplingType((Abc::uint32_t)frames.size(), timePerCycle); AbcA::TimeSampling sampling(samplingType, frames); mTs = mArchive.addTimeSampling(sampling); } else { AbcA::TimeSampling sampling(1.0, frames[0]); mTs = mArchive.addTimeSampling(sampling); } Abc::OBox3dProperty boxProp = AbcG::CreateOArchiveBounds(mArchive, mTs); MDagPath dagPath; { MItDag().getPath(dagPath); } SceneNodePtr exoSceneRoot = buildMayaSceneGraph(dagPath, this->replacer); const bool bFlattenHierarchy = GetOption("flattenHierarchy") == "1"; const bool bTransformCache = GetOption("transformCache") == "1"; const bool bSelectChildren = false; { std::map<std::string, bool> selectionMap; for (int i = 0; i < (int)mSelection.length(); ++i) { MFnDagNode dagNode(mSelection[i]); selectionMap[dagNode.fullPathName().asChar()] = true; } selectNodes(exoSceneRoot, selectionMap, !bFlattenHierarchy || bTransformCache, bSelectChildren, !bTransformCache, true); } // create object for each MProgressWindow::reserve(); MProgressWindow::setTitle("Alembic Export: Listing objects"); MProgressWindow::setInterruptable(true); MProgressWindow::setProgressRange(0, mSelection.length()); MProgressWindow::setProgress(0); MProgressWindow::startProgress(); int interrupt = 20; bool processStopped = false; std::deque<PreProcessStackElement> sceneStack; sceneStack.push_back(PreProcessStackElement(exoSceneRoot, mTop)); while (!sceneStack.empty()) { if (--interrupt == 0) { interrupt = 20; if (MProgressWindow::isCancelled()) { processStopped = true; break; } } PreProcessStackElement &sElement = sceneStack.back(); SceneNodePtr eNode = sElement.eNode; sceneStack.pop_back(); Abc::OObject oParent = sElement.oParent; Abc::OObject oNewParent; AlembicObjectPtr pNewObject; if (eNode->selected) { switch (eNode->type) { case SceneNode::SCENE_ROOT: break; case SceneNode::ITRANSFORM: case SceneNode::ETRANSFORM: pNewObject.reset(new AlembicXform(eNode, this, oParent)); break; case SceneNode::CAMERA: pNewObject.reset(new AlembicCamera(eNode, this, oParent)); break; case SceneNode::POLYMESH: pNewObject.reset(new AlembicPolyMesh(eNode, this, oParent)); break; case SceneNode::SUBD: pNewObject.reset(new AlembicSubD(eNode, this, oParent)); break; case SceneNode::CURVES: pNewObject.reset(new AlembicCurves(eNode, this, oParent)); break; case SceneNode::PARTICLES: pNewObject.reset(new AlembicPoints(eNode, this, oParent)); break; case SceneNode::HAIR: pNewObject.reset(new AlembicHair(eNode, this, oParent)); break; default: ESS_LOG_WARNING("Unknown type: not exporting " << eNode->name); } } if (pNewObject) { AddObject(pNewObject); oNewParent = oParent.getChild(eNode->name); } else { oNewParent = oParent; } if (oNewParent.valid()) { for (std::list<SceneNodePtr>::iterator it = eNode->children.begin(); it != eNode->children.end(); ++it) { if (!bFlattenHierarchy || (bFlattenHierarchy && eNode->type == SceneNode::ETRANSFORM && isShapeNode((*it)->type))) { // If flattening the hierarchy, we want to attach each external // transform to its corresponding geometry node. // All internal transforms should be skipped. Geometry nodes will // never have children (If and XSI geonode is parented // to another geonode, each will be parented to its extracted // transform node, and one node will be parented to the // transform of the other. sceneStack.push_back(PreProcessStackElement(*it, oNewParent)); } else { // if we skip node A, we parent node A's children to the parent of A sceneStack.push_back(PreProcessStackElement(*it, oParent)); } } } //* else { ESS_LOG_ERROR("Do not have reference to parent."); MPxCommand::setResult( "Error caught in AlembicWriteJob::PreProcess: do not have " "reference to parent"); return MS::kFailure; } //*/ } MProgressWindow::endProgress(); return processStopped ? MStatus::kEndOfFile : MStatus::kSuccess; } catch (AbcU::Exception &e) { this->forceCloseArchive(); MString exc(e.what()); MGlobal::displayError("[ExocortexAlembic] Error writing to file '" + mFileName + "' (" + exc + "). Do you still have it opened?"); MPxCommand::setResult( "Error caught in AlembicWriteJob::PreProcess: error writing file"); } return MS::kFailure; }
/** * Build the animation from Maya MotionPath */ osg::ref_ptr<osg::AnimationPath> Transform::motionPath2AnimationPath(MObject &obj) { osg::ref_ptr<osg::AnimationPath> anim = new osg::AnimationPath(); // STEP 1. Get the animation curve from this MotionPath MFnMotionPath motion; MFnDependencyNode dn(obj); MPlugArray conns; dn.getConnections(conns); for(int i=0; i<conns.length(); i++){ MPlug conn = conns[i]; MPlugArray connectedTo; // Get the connections having this node as destination conn.connectedTo(connectedTo, true, false); for(int j=0; j<connectedTo.length(); j++){ MPlug origin = connectedTo[j]; MObject origin_node = origin.node(); if(origin_node.hasFn(MFn::kMotionPath)){ motion.setObject(origin_node); break; } } } MFnAnimCurve anim_curve; dn.setObject(motion.object()); dn.getConnections(conns); for(int i=0; i<conns.length(); i++){ MPlug conn = conns[i]; MPlugArray connectedTo; // Get the connections having this node as destination conn.connectedTo(connectedTo, true, false); for(int j=0; j<connectedTo.length(); j++){ MPlug origin = connectedTo[j]; MObject origin_node = origin.node(); if(origin_node.hasFn(MFn::kAnimCurve)){ anim_curve.setObject(origin_node); break; } } } // STEP 2 ... // STEP 3. Benefits! for(int i=0; i<anim_curve.numKeys(); i++){ MTime t = anim_curve.time(i); double time = t.as(MTime::kSeconds); MAnimControl::setCurrentTime(MTime(time,MTime::kSeconds)); anim->insert(time, osg::AnimationPath::ControlPoint( getCPPosition(obj), getCPRotation(obj), getCPScale(obj) )); } return anim; }
void ParamList::parseArgs(const MArgList &args) { MStatus stat; // Parse arguments from command line for (unsigned int i = 0; i < args.length(); i++ ) { if ((MString("-all") == args.asString(i,&stat)) && (MS::kSuccess == stat)) exportAll = true; else if ((MString("-world") == args.asString(i,&stat)) && (MS::kSuccess == stat)) exportWorldCoords = true; else if ((MString("-mesh") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { exportMesh = true; meshFilename = args.asString(++i,&stat); } else if ((MString("-mat") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { exportMaterial = true; materialFilename = args.asString(++i,&stat); } else if ((MString("-matPrefix") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { matPrefix = args.asString(++i,&stat); } else if ((MString("-copyTex") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { copyTextures = true; texOutputDir = args.asString(++i,&stat); } else if ((MString("-lightOff") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { lightingOff = true; } else if ((MString("-skel") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { exportSkeleton = true; skeletonFilename = args.asString(++i,&stat); } else if ((MString("-anims") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { exportAnims = true; } else if ((MString("-animCur") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { exportAnimCurves = true; animFilename = args.asString(++i,&stat); } else if ((MString("-cam") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { exportCameras = true; camerasFilename = args.asString(++i,&stat); } else if ((MString("-v") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { exportVBA = true; } else if ((MString("-n") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { exportVertNorm = true; } else if ((MString("-c") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { exportVertCol = true; } else if ((MString("-cw") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { exportVertCol = true; exportVertColWhite = true; } else if ((MString("-t") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { exportTexCoord = true; } else if ((MString("-camAnim") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { exportCamerasAnim = true; } else if ((MString("-meshbin") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { exportMeshBin = true; } else if ((MString("-skelbin") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { exportSkelBin = true; } else if ((MString("-particles") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { exportParticles = true; particlesFilename = args.asString(++i,&stat); } else if ((MString("-shared") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { useSharedGeom = true; } else if ((MString("-np") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { MString npType = args.asString(i,&stat); if (npType == "curFrame") neutralPoseType = NPT_CURFRAME; else if (npType == "bindPose") neutralPoseType = NPT_BINDPOSE; else if (npType == "frame") { neutralPoseType = NPT_FRAME; neutralPoseFrame = args.asInt(++i,&stat); } } else if ((MString("-clip") == args.asString(i,&stat)) && (MS::kSuccess == stat)) { //get clip name MString clipName = args.asString(++i,&stat); //get clip range MString clipRangeType = args.asString(++i,&stat); double startTime, stopTime; if (clipRangeType == "startEnd") { startTime = args.asDouble(++i,&stat); stopTime = args.asDouble(++i,&stat); MString rangeUnits = args.asString(++i,&stat); if (rangeUnits == "frames") { //range specified in frames => convert to seconds MTime t1(startTime, MTime::uiUnit()); MTime t2(stopTime, MTime::uiUnit()); startTime = t1.as(MTime::kSeconds); stopTime = t2.as(MTime::kSeconds); } } else { //range specified by time slider MTime t1 = MAnimControl::minTime(); MTime t2 = MAnimControl::maxTime(); startTime = t1.as(MTime::kSeconds); stopTime = t2.as(MTime::kSeconds); } // get sample rate double rate; MString sampleRateType = args.asString(++i,&stat); if (sampleRateType == "sampleByFrames") { // rate specified in frames int intRate = args.asInt(++i,&stat); MTime t = MTime(intRate, MTime::uiUnit()); rate = t.as(MTime::kSeconds); } else { // rate specified in seconds rate = args.asDouble(++i,&stat); } //add clip info clipInfo clip; clip.name = clipName; clip.start = startTime; clip.stop = stopTime; clip.rate = rate; clipList.push_back(clip); std::cout << "clip " << clipName.asChar() << "\n"; std::cout << "start: " << startTime << ", stop: " << stopTime << "\n"; std::cout << "rate: " << rate << "\n"; std::cout << "-----------------\n"; } } /* // Read options from exporter window // Gather clips data // Read info about the clips we have to transform int numClips,exportClip,rangeType,rateType,rangeUnits; double startTime,stopTime,rate; MString clipName; //read number of clips MGlobal::executeCommand("eval \"$numClips+=0\"",numClips,false); //read clips data for (int i=1; i<=numClips; i++) { MString command = "checkBox -q -v ExportClip"; command += i; MGlobal::executeCommand(command,exportClip,false); if (exportClip) { //get clip name command = "textField -q -tx ClipName"; command += i; MGlobal::executeCommand(command,clipName,false); //get clip range command = "radioButtonGrp -q -sl ClipRangeRadio"; command += i; MGlobal::executeCommand(command,rangeType,false); if (rangeType == 1) { //range specified from user command = "floatField -q -v ClipRangeStart"; command += i; MGlobal::executeCommand(command,startTime,false); command = "floatField -q -v ClipRangeEnd"; command += i; MGlobal::executeCommand(command,stopTime,false); //get range units command = "radioButtonGrp -q -sl ClipRangeUnits"; command += i; MGlobal::executeCommand(command,rangeUnits,false); if (rangeUnits == 1) { //range specified in frames => convert to seconds MTime t1(startTime, MTime::uiUnit()); MTime t2(stopTime, MTime::uiUnit()); startTime = t1.as(MTime::kSeconds); stopTime = t2.as(MTime::kSeconds); } } else { //range specified by time slider MTime t1 = MAnimControl::minTime(); MTime t2 = MAnimControl::maxTime(); startTime = t1.as(MTime::kSeconds); stopTime = t2.as(MTime::kSeconds); } //get sample rate command = "radioButtonGrp -q -sl ClipRateType"; command += i; MGlobal::executeCommand(command,rateType,false); MTime t; switch (rateType) { case 1: //rate specified in frames command = "intField -q -v ClipRateFrames"; command += i; MGlobal::executeCommand(command,rate,false); t = MTime(rate, MTime::uiUnit()); rate = t.as(MTime::kSeconds); break; case 2: //rate specified in seconds command = "floatField -q -v ClipRateSeconds"; command += i; MGlobal::executeCommand(command,rate,false); break; default://rate not specified, get from time slider rate = -1; break; } //add clip info clipInfo clip; clip.name = clipName; clip.start = startTime; clip.stop = stopTime; clip.rate = rate; clipList.push_back(clip); std::cout << "clip " << clipName.asChar() << "\n"; std::cout << "start: " << startTime << ", stop: " << stopTime << "\n"; std::cout << "rate: " << rate << "\n"; std::cout << "-----------------\n"; } }*/ }
//-***************************************************************************** MStatus AbcExportSelected( const Parameters &iConfig ) { // Abc::Init(); //-************************************************************************* // CREATE SELECTION LIST //-************************************************************************* MSelectionList slist; MGlobal::getActiveSelectionList( slist ); if ( slist.length() == 0 ) { MGlobal::displayError( "Nothing selected." ); return MS::kFailure; } //-************************************************************************* // CREATE THE ARCHIVE //-************************************************************************* if ( iConfig.fileName == "UNSPECIFIED_FILE_NAME.abc" || iConfig.fileName == "" ) { MGlobal::displayError( "No filename specified." ); return MStatus::kFailure; } // Create the time sampling. Abc::TimeSamplingType tSmpType; if ( iConfig.endFrame > iConfig.startFrame ) { tSmpType = Abc::TimeSamplingType( // Increment, in seconds, between samples. ( Abc::chrono_t ) MTime( 1.0, MTime::uiUnit() ).as( MTime::kSeconds ) ); } // Get FPS Abc::chrono_t fps = MTime( 1.0, MTime::kSeconds ).as( MTime::uiUnit() ); Top top( iConfig.fileName, tSmpType, fps ); std::cout << "AlembicSimpleAbcExport: Opened Alembic Archive: " << top.getName() << " for writing." << std::endl; // Build comments std::string comments = "AlembicSimpleAbcExport v0.1.1"; comments += "\n"; MString exportedFromStr = "(Exported from " + MFileIO::currentFile() + ")"; comments += exportedFromStr.asChar(); comments += "\n"; // top.setComments( comments ); //-********************************************************************* // BUILD TREE OF NODE:OBJECT PAIRS TO EXPORT //-********************************************************************* // Create the factory Factory factory( iConfig ); for ( MItSelectionList liter( slist ); !liter.isDone(); liter.next() ) { MDagPath dagPath; MObject component; liter.getDagPath( dagPath, component ); // This will skip nodes we've already visited. HAVE NO // FEAR. factory.makeTree( top, dagPath, 1000000, tSmpType ); } std::cout << "AlembicSimpleAbcExport: Created DAG Tree to export." << std::endl; //-********************************************************************* // EXPORT SAMPLES PER FRAME //-********************************************************************* // Loop over time MComputation computation; computation.beginComputation(); for ( int frame = iConfig.startFrame; frame <= iConfig.endFrame; ++frame ) { // Get a time. MTime thisTime( ( double )frame, MTime::uiUnit() ); // Set the time. MAnimControl::setCurrentTime( thisTime ); // Get the chrono and the index Abc::index_t frameIndex = ( Abc::index_t )( frame - iConfig.startFrame ); Abc::chrono_t frameTime = ( Abc::chrono_t )thisTime.as( MTime::kSeconds ); // Is this necessary to force an eval? Sometimes? // MGlobal::viewFrame( t ); // M3dView currentView = M3dView::active3dView(); // currentView.refresh( true, true, true ); // Write the frame. top.writeSample( Abc::OSampleSelector( frameIndex, frameTime ) ); std::cout << "AlembicSimpleAbcExport: Wrote frame: " << frame << std::endl; if ( computation.isInterruptRequested() ) { break; } } top.close(); computation.endComputation(); // H5close(); std::cout << "AlembicSimpleAbcExport: Closed Archive." << std::endl; return MS::kSuccess; }
/* static */ bool PxrUsdMayaTranslatorCurves::Create( const UsdGeomCurves& curves, MObject parentNode, const PxrUsdMayaPrimReaderArgs& args, PxrUsdMayaPrimReaderContext* context) { if (not curves) { return false; } const UsdPrim& prim = curves.GetPrim(); MStatus status; // Create node (transform) MObject mayaNodeTransformObj; if (not PxrUsdMayaTranslatorUtil::CreateTransformNode(prim, parentNode, args, context, &status, &mayaNodeTransformObj)) { return false; } VtArray<GfVec3f> points; VtArray<int> curveOrder; VtArray<int> curveVertexCounts; VtArray<float> curveWidths; VtArray<GfVec2d> curveRanges; VtArray<double> curveKnots; // LIMITATION: xxx REVISIT xxx // Non-animated Attrs // Assuming that a number of these USD attributes are assumed to not be animated // Some we may want to expose as animatable later. // curves.GetCurveVertexCountsAttr().Get(&curveVertexCounts); // not animatable // XXX: // Only supporting single curve for now. // Sanity Checks if (curveVertexCounts.size() == 0) { MGlobal::displayError( TfStringPrintf("VertexCount arrays is empty on NURBS curves <%s>. Skipping...", prim.GetPath().GetText()).c_str()); return false; // No verts for the curve, so exit } else if (curveVertexCounts.size() > 1) { MGlobal::displayWarning( TfStringPrintf("Multiple curves in <%s>. Reading first one...", prim.GetPath().GetText()).c_str()); } int curveIndex = 0; curves.GetWidthsAttr().Get(&curveWidths); // not animatable // Gather points. If args.GetReadAnimData() is TRUE, // pick the first avaiable sample or default UsdTimeCode pointsTimeSample=UsdTimeCode::EarliestTime(); std::vector<double> pointsTimeSamples; size_t numTimeSamples = 0; if (args.GetReadAnimData()) { curves.GetPointsAttr().GetTimeSamples(&pointsTimeSamples); numTimeSamples = pointsTimeSamples.size(); if (numTimeSamples>0) { pointsTimeSample = pointsTimeSamples[0]; } } curves.GetPointsAttr().Get(&points, pointsTimeSample); if (points.size() == 0) { MGlobal::displayError( TfStringPrintf("Points arrays is empty on NURBS curves <%s>. Skipping...", prim.GetPath().GetText()).c_str()); return false; // invalid nurbscurves, so exit } if (UsdGeomNurbsCurves nurbsSchema = UsdGeomNurbsCurves(prim)) { nurbsSchema.GetOrderAttr().Get(&curveOrder); // not animatable nurbsSchema.GetKnotsAttr().Get(&curveKnots); // not animatable nurbsSchema.GetRangesAttr().Get(&curveRanges); // not animatable } else { // Handle basis curves originally modelled in Maya as nurbs. curveOrder.resize(1); UsdGeomBasisCurves basisSchema = UsdGeomBasisCurves(prim); TfToken typeToken; basisSchema.GetTypeAttr().Get(&typeToken); if (typeToken == UsdGeomTokens->linear) { curveOrder[0] = 2; curveKnots.resize(points.size()); for (size_t i=0; i < curveKnots.size(); ++i) { curveKnots[i] = i; } } else { curveOrder[0] = 4; // Strip off extra end points; assuming this is non-periodic. VtArray<GfVec3f> tmpPts(points.size() - 2); std::copy(points.begin() + 1, points.end() - 1, tmpPts.begin()); points.swap(tmpPts); // Cubic curves in Maya have numSpans + 2*3 - 1, and for geometry // that came in as basis curves, we have numCV's - 3 spans. See the // MFnNurbsCurve documentation and the nurbs curve export // implementation in mojitoplugmaya for more details. curveKnots.resize(points.size() -3 + 5); int knotIdx = 0; for (size_t i=0; i < curveKnots.size(); ++i) { if (i < 3) { curveKnots[i] = 0.0; } else { if (i <= curveKnots.size() - 3) { ++knotIdx; } curveKnots[i] = double(knotIdx); } } } } // == Convert data size_t mayaNumVertices = points.size(); MPointArray mayaPoints(mayaNumVertices); for (size_t i=0; i < mayaNumVertices; i++) { mayaPoints.set( i, points[i][0], points[i][1], points[i][2] ); } double *knots=curveKnots.data(); MDoubleArray mayaKnots( knots, curveKnots.size()); int mayaDegree = curveOrder[curveIndex] - 1; MFnNurbsCurve::Form mayaCurveForm = MFnNurbsCurve::kOpen; // HARDCODED bool mayaCurveCreate2D = false; bool mayaCurveCreateRational = true; // == Create NurbsCurve Shape Node MFnNurbsCurve curveFn; MObject curveObj = curveFn.create(mayaPoints, mayaKnots, mayaDegree, mayaCurveForm, mayaCurveCreate2D, mayaCurveCreateRational, mayaNodeTransformObj, &status ); if (status != MS::kSuccess) { return false; } MString nodeName( prim.GetName().GetText() ); nodeName += "Shape"; curveFn.setName(nodeName, false, &status); std::string nodePath( prim.GetPath().GetText() ); nodePath += "/"; nodePath += nodeName.asChar(); if (context) { context->RegisterNewMayaNode( nodePath, curveObj ); // used for undo/redo } // == Animate points == // Use blendShapeDeformer so that all the points for a frame are contained in a single node // Almost identical code as used with MayaMeshReader.cpp // if (numTimeSamples > 0) { MPointArray mayaPoints(mayaNumVertices); MObject curveAnimObj; MFnBlendShapeDeformer blendFn; MObject blendObj = blendFn.create(curveObj); if (context) { context->RegisterNewMayaNode(blendFn.name().asChar(), blendObj ); // used for undo/redo } for (unsigned int ti=0; ti < numTimeSamples; ++ti) { curves.GetPointsAttr().Get(&points, pointsTimeSamples[ti]); for (unsigned int i=0; i < mayaNumVertices; i++) { mayaPoints.set( i, points[i][0], points[i][1], points[i][2] ); } // == Create NurbsCurve Shape Node MFnNurbsCurve curveFn; if ( curveAnimObj.isNull() ) { curveAnimObj = curveFn.create(mayaPoints, mayaKnots, mayaDegree, mayaCurveForm, mayaCurveCreate2D, mayaCurveCreateRational, mayaNodeTransformObj, &status ); if (status != MS::kSuccess) { continue; } } else { // Reuse the already created curve by copying it and then setting the points curveAnimObj = curveFn.copy(curveAnimObj, mayaNodeTransformObj, &status); curveFn.setCVs(mayaPoints); } blendFn.addTarget(curveObj, ti, curveAnimObj, 1.0); curveFn.setIntermediateObject(true); if (context) { context->RegisterNewMayaNode( curveFn.fullPathName().asChar(), curveAnimObj ); // used for undo/redo } } // Animate the weights so that curve0 has a weight of 1 at frame 0, etc. MFnAnimCurve animFn; // Construct the time array to be used for all the keys MTimeArray timeArray; timeArray.setLength(numTimeSamples); for (unsigned int ti=0; ti < numTimeSamples; ++ti) { timeArray.set( MTime(pointsTimeSamples[ti]), ti); } // Key/Animate the weights MPlug plgAry = blendFn.findPlug( "weight" ); if ( !plgAry.isNull() && plgAry.isArray() ) { for (unsigned int ti=0; ti < numTimeSamples; ++ti) { MPlug plg = plgAry.elementByLogicalIndex(ti, &status); MDoubleArray valueArray(numTimeSamples, 0.0); valueArray[ti] = 1.0; // Set the time value where this curve's weight should be 1.0 MObject animObj = animFn.create(plg, NULL, &status); animFn.addKeys(&timeArray, &valueArray); if (context) { context->RegisterNewMayaNode(animFn.name().asChar(), animObj ); // used for undo/redo } } } } return true; }
// Load an animation clip MStatus skeleton::loadClip(MString clipName,int start,int stop,int rate) { uint fps = getFps(); float frameTime = 1000.0f / fps; MStatus stat; int i,j; std::vector<int> times; if (m_joints.size() < 0) return MS::kFailure; times.clear(); for (int t=start; t<stop; t+=rate) times.push_back(t); times.push_back(stop); // create the animation animation a; a.name = clipName.asChar(); if(m_animations.size() == 0) { a.startTime = 0; a.endTime = times[times.size()-1] - times[0]; } else { a.startTime = m_animations[m_animations.size()-1].endTime + 1; a.endTime = a.startTime + times[times.size()-1] - times[0]; } m_animations.push_back(a); int animIdx = m_animations.size() - 1; for (i=0; i<times.size(); i++) { MAnimControl::setCurrentTime(MTime(times[i],MTime::uiUnit())); for (j=0; j<m_joints.size(); j++) { keyframeTranslation translation; keyframeRotation rotation; keyframeScale scale; joint &jt = m_joints[j]; int time = times[i] - times[0] + a.startTime; loadKeyframe(m_joints[j],time,translation,rotation,scale); translation.time *= frameTime; rotation.time *= frameTime; scale.time *= frameTime; size_t size = jt.keyframesTranslation.size(); if(size > 0) { keyframeTranslation& t = jt.keyframesTranslation[size - 1]; if(!equal(translation.v[0],t.v[0]) || !equal(translation.v[1],t.v[1]) || !equal(translation.v[2],t.v[2])) { //如果跟上一次不一样,并且跨越了桢,那么需要补一桢 int lastTime = Round(t.time / frameTime); if(time - 1 > lastTime) { keyframeTranslation temp = t; temp.time = (time - 1) * frameTime; jt.keyframesTranslation.push_back(temp); } jt.keyframesTranslation.push_back(translation); } } else { jt.keyframesTranslation.push_back(translation); } MFnIkJoint jn(jt.jointDag); if(jn.name() == "Hips") { // breakable; } size = jt.keyframesRotation.size(); if(size > 0) { keyframeRotation& r = jt.keyframesRotation[size - 1]; if(!equal(rotation.q[0],r.q[0]) || !equal(rotation.q[1],r.q[1]) || !equal(rotation.q[2],r.q[2]) || !equal(rotation.q[3],r.q[3])) { //如果跟上一次不一样,并且跨越了桢,那么需要补一桢 int lastTime = Round(r.time / frameTime); if(time - 1 > lastTime) { keyframeRotation temp = r; temp.time = (time - 1) * frameTime; jt.keyframesRotation.push_back(temp); } jt.keyframesRotation.push_back(rotation); } } else { jt.keyframesRotation.push_back(rotation); } size = jt.keyframesScale.size(); if(size > 0) { keyframeScale& s = jt.keyframesScale[size - 1]; if(!equal(scale.v[0],s.v[0]) || !equal(scale.v[1],s.v[1]) || !equal(scale.v[2],s.v[2])) { //如果跟上一次不一样,并且跨越了桢,那么需要补一桢 int lastTime = Round(s.time / frameTime); if(time - 1 > lastTime) { keyframeScale temp = s; temp.time = (time - 1) * frameTime; jt.keyframesScale.push_back(temp); } jt.keyframesScale.push_back(scale); } } else { jt.keyframesScale.push_back(scale); } if(jt.hasRibbonSystem) { keyframeT<bool> keyframeVisible; keyframeT<float> keyframeAbove; keyframeT<float> keyframeBelow; keyframeT<short> keyframeSlot; keyframeT<float3> keyframeColor; keyframeT<float> keyframeAlpha; MFnIkJoint jointFn(jt.jointDag); MPlug plug; plug = jointFn.findPlug("unRibbonVisible"); bool visible; plug.getValue(visible); plug = jointFn.findPlug("unRibbonAbove"); float above; plug.getValue(above); plug = jointFn.findPlug("unRibbonBelow"); float below; plug.getValue(below); plug = jointFn.findPlug("unRibbonTextureSlot"); short slot; plug.getValue(slot); plug = jointFn.findPlug("unRibbonVertexColor"); MObject object; plug.getValue(object); MFnNumericData data(object); float r,g,b; data.getData(r,g,b); plug = jointFn.findPlug("unRibbonVertexAlpha"); float alpha; plug.getValue(alpha); keyframeVisible.time = time * frameTime; keyframeAbove.time = time * frameTime; keyframeBelow.time = time * frameTime; keyframeSlot.time = time * frameTime; keyframeColor.time = time * frameTime; keyframeAlpha.time = time * frameTime; keyframeVisible.data = visible; keyframeAbove.data = above; keyframeBelow.data = below; keyframeSlot.data = slot; keyframeColor.data[0] = r; keyframeColor.data[1] = g; keyframeColor.data[2] = b; keyframeAlpha.data = alpha; addKeyFramesBool(&jt.ribbon.keyframesVisible,&keyframeVisible); addKeyFramesFloat(&jt.ribbon.keyframeAbove,&keyframeAbove); addKeyFramesFloat(&jt.ribbon.keyframeBelow,&keyframeBelow); size = jt.ribbon.keyframeSlot.size(); if(size > 0) { keyframeT<short>& s = jt.ribbon.keyframeSlot[size - 1]; if(s.data == slot) { jt.ribbon.keyframeSlot.push_back(keyframeSlot); } } else { jt.ribbon.keyframeSlot.push_back(keyframeSlot); } size = jt.ribbon.keyframeColor.size(); if(size > 0) { keyframeT<float3>& s = jt.ribbon.keyframeColor[size - 1]; if(!equal(s.data[0],r) || !equal(s.data[1],g) || !equal(s.data[2],b)) { jt.ribbon.keyframeColor.push_back(keyframeColor); } } else { jt.ribbon.keyframeColor.push_back(keyframeColor); } addKeyFramesFloat(&jt.ribbon.keyframeAlpha,&keyframeAlpha); } if(jt.hasParticleSystem) { keyframeT<bool> keyframeVisible; keyframeT<float> keyframeSpeed; keyframeT<float> keyframeVariation; keyframeT<float> keyframeConeAngle; keyframeT<float> keyframeGravity; keyframeT<float> keyframeExplosiveForce; keyframeT<float> keyframeEmissionRate; keyframeT<float> keyframeWidth; keyframeT<float> keyframeLength; keyframeT<float> keyframeHeight; MFnIkJoint jointFn(jt.jointDag); MPlug plug; plug = jointFn.findPlug("unParticleVisible"); bool visible; plug.getValue(visible); plug = jointFn.findPlug("unParticleSpeed"); float speed; plug.getValue(speed); plug = jointFn.findPlug("unParticleVariationPercent"); float variation; plug.getValue(variation); plug = jointFn.findPlug("unParticleConeAngle"); float coneAngle; plug.getValue(coneAngle); plug = jointFn.findPlug("unParticleGravity"); float gravity; plug.getValue(gravity); plug = jointFn.findPlug("unParticleExplosiveForce"); float explosiveForce = 0.0f; if(!plug.isNull()) { plug.getValue(explosiveForce); } plug = jointFn.findPlug("unParticleEmissionRate"); float emissionRate; plug.getValue(emissionRate); plug = jointFn.findPlug("unParticleEmitterWidth"); float width; plug.getValue(width); plug = jointFn.findPlug("unParticleEmitterLength"); float length; plug.getValue(length); plug = jointFn.findPlug("unParticleEmitterHeight"); float height = 0.0f; if(!plug.isNull()) { plug.getValue(height); } keyframeVisible.time = time * frameTime; keyframeSpeed.time = time * frameTime; keyframeVariation.time = time * frameTime; keyframeConeAngle.time = time * frameTime; keyframeGravity.time = time * frameTime; keyframeExplosiveForce.time = time * frameTime; keyframeEmissionRate.time = time * frameTime; keyframeWidth.time = time * frameTime; keyframeLength.time = time * frameTime; keyframeHeight.time = time * frameTime; keyframeVisible.data = visible; keyframeSpeed.data = speed; keyframeVariation.data = variation / 100.0f; keyframeConeAngle.data = coneAngle; keyframeGravity.data = gravity; keyframeExplosiveForce.data = explosiveForce; keyframeEmissionRate.data = emissionRate; keyframeWidth.data = width; keyframeLength.data = length; keyframeHeight.data = height; addKeyFramesBool(&jt.particle.keyframesVisible,&keyframeVisible); addKeyFramesFloat(&jt.particle.keyframesSpeed,&keyframeSpeed); addKeyFramesFloat(&jt.particle.keyframesVariation,&keyframeVariation); addKeyFramesFloat(&jt.particle.keyframesConeAngle,&keyframeConeAngle); addKeyFramesFloat(&jt.particle.keyframesGravity,&keyframeGravity); addKeyFramesFloat(&jt.particle.keyframesExplosiveForce,&keyframeExplosiveForce); addKeyFramesFloat(&jt.particle.keyframesEmissionRate,&keyframeEmissionRate); addKeyFramesFloat(&jt.particle.keyframesWidth,&keyframeWidth); addKeyFramesFloat(&jt.particle.keyframesLength,&keyframeLength); addKeyFramesFloat(&jt.particle.keyframesHeight,&keyframeHeight); } } } return MS::kSuccess; }
void NifAnimationImporter::ImportControllers( NiAVObjectRef niAVObj, MDagPath & path ) { list<NiTimeControllerRef> controllers = niAVObj->GetControllers(); //Iterate over the controllers, reacting properly to each type for ( list<NiTimeControllerRef>::iterator it = controllers.begin(); it != controllers.end(); ++it ) { if ( (*it)->IsDerivedType( NiKeyframeController::TYPE ) ) { //--NiKeyframeController--// NiKeyframeControllerRef niKeyCont = DynamicCast<NiKeyframeController>(*it); NiKeyframeDataRef niKeyData = niKeyCont->GetData(); MFnTransform transFn( path.node() ); MFnAnimCurve traXFn; MFnAnimCurve traYFn; MFnAnimCurve traZFn; MObject traXcurve = traXFn.create( transFn.findPlug("translateX") ); MObject traYcurve = traYFn.create( transFn.findPlug("translateY") ); MObject traZcurve = traZFn.create( transFn.findPlug("translateZ") ); MTimeArray traTimes; MDoubleArray traXValues; MDoubleArray traYValues; MDoubleArray traZValues; vector<Key<Vector3> > tra_keys = niKeyData->GetTranslateKeys(); for ( size_t i = 0; i < tra_keys.size(); ++i) { traTimes.append( MTime( tra_keys[i].time, MTime::kSeconds ) ); traXValues.append( tra_keys[i].data.x ); traYValues.append( tra_keys[i].data.y ); traZValues.append( tra_keys[i].data.z ); //traXFn.addKeyframe( tra_keys[i].time * 24.0, tra_keys[i].data.x ); //traYFn.addKeyframe( tra_keys[i].time * 24.0, tra_keys[i].data.y ); //traZFn.addKeyframe( tra_keys[i].time * 24.0, tra_keys[i].data.z ); } traXFn.addKeys( &traTimes, &traXValues ); traYFn.addKeys( &traTimes, &traYValues ); traZFn.addKeys( &traTimes, &traZValues ); KeyType kt = niKeyData->GetRotateType(); if ( kt != XYZ_ROTATION_KEY ) { vector<Key<Quaternion> > rot_keys = niKeyData->GetQuatRotateKeys(); MFnAnimCurve rotXFn; MFnAnimCurve rotYFn; MFnAnimCurve rotZFn; MObject rotXcurve = rotXFn.create( transFn.findPlug("rotateX") ); //rotXFn.findPlug("rotationInterpolation").setValue(3); MObject rotYcurve = rotYFn.create( transFn.findPlug("rotateY") ); //rotYFn.findPlug("rotationInterpolation").setValue(3); MObject rotZcurve = rotZFn.create( transFn.findPlug("rotateZ") ); //rotZFn.findPlug("rotationInterpolation").setValue(3); MTimeArray rotTimes; MDoubleArray rotXValues; MDoubleArray rotYValues; MDoubleArray rotZValues; MEulerRotation mPrevRot; for( size_t i = 0; i < rot_keys.size(); ++i ) { Quaternion niQuat = rot_keys[i].data; MQuaternion mQuat( niQuat.x, niQuat.y, niQuat.z, niQuat.w ); MEulerRotation mRot = mQuat.asEulerRotation(); MEulerRotation mAlt; mAlt[0] = PI + mRot[0]; mAlt[1] = PI - mRot[1]; mAlt[2] = PI + mRot[2]; for ( size_t j = 0; j < 3; ++j ) { double prev_diff = abs(mRot[j] - mPrevRot[j]); //Try adding and subtracting multiples of 2 pi radians to get //closer to the previous angle while (true) { double new_angle = mRot[j] - (PI * 2); double diff = abs( new_angle - mPrevRot[j] ); if ( diff < prev_diff ) { mRot[j] = new_angle; prev_diff = diff; } else { break; } } while (true) { double new_angle = mRot[j] + (PI * 2); double diff = abs( new_angle - mPrevRot[j] ); if ( diff < prev_diff ) { mRot[j] = new_angle; prev_diff = diff; } else { break; } } } for ( size_t j = 0; j < 3; ++j ) { double prev_diff = abs(mAlt[j] - mPrevRot[j]); //Try adding and subtracting multiples of 2 pi radians to get //closer to the previous angle while (true) { double new_angle = mAlt[j] - (PI * 2); double diff = abs( new_angle - mPrevRot[j] ); if ( diff < prev_diff ) { mAlt[j] = new_angle; prev_diff = diff; } else { break; } } while (true) { double new_angle = mAlt[j] + (PI * 2); double diff = abs( new_angle - mPrevRot[j] ); if ( diff < prev_diff ) { mAlt[j] = new_angle; prev_diff = diff; } else { break; } } } //Try taking advantage of the fact that: //Rotate(x,y,z) = Rotate(pi + x, pi - y, pi +z) double rot_diff = ( (abs(mRot[0] - mPrevRot[0]) + abs(mRot[1] - mPrevRot[1]) + abs(mRot[2] - mPrevRot[2]) ) / 3.0 ); double alt_diff = ( (abs(mAlt[0] - mPrevRot[0]) + abs(mAlt[1] - mPrevRot[1]) + abs(mAlt[2] - mPrevRot[2]) ) / 3.0 ); if ( alt_diff < rot_diff ) { mRot = mAlt; } mPrevRot = mRot; rotTimes.append( MTime(rot_keys[i].time, MTime::kSeconds) ); rotXValues.append( mRot[0] ); rotYValues.append( mRot[1] ); rotZValues.append( mRot[2] ); } rotXFn.addKeys( &rotTimes, &rotXValues ); rotYFn.addKeys( &rotTimes, &rotYValues ); rotZFn.addKeys( &rotTimes, &rotZValues ); } } } }
void cStructLoader::Load(bool reload) { if(SL_TSTFLAG(SL_DISABLED) || (reload && !SL_TSTFLAG(SL_WATCH))) return; FILE *f=fopen(path,"r"); if(f) { PreLoad(); int curr_mtime=MTime(true); ListLock(true); bool doload=false; if(!reload) { Clear(); Modified(false); mtime=curr_mtime; doload=true; } else if(mtime<curr_mtime) { PRINTF(L_CORE_LOAD,"detected change of %s",path); if(IsModified()) PRINTF(L_CORE_LOAD,"discarding in-memory changes"); for(cStructItem *a=First(); a; a=Next(a)) DelItem(a); Modified(false); mtime=curr_mtime; doload=true; } if(doload) { SL_SETFLAG(SL_LOADED); PRINTF(L_GEN_INFO,"loading %s from %s",type,path); CheckAccess(); int lineNum=0, num=0; char buff[4096]; while(fgets(buff,sizeof(buff),f)) { lineNum++; if(!index(buff,'\n') && !feof(f)) { PRINTF(L_GEN_ERROR,"file %s readbuffer overflow line#%d",path,lineNum); SL_CLRFLAG(SL_LOADED); break; } strreplace(buff,'\n',0); strreplace(buff,'\r',0); // chomp bool hasContent=false; char *ls; for(ls=buff; *ls; ls++) { if(*ls==';' || *ls=='#') { // comment if(hasContent) while(ls>buff && ls[-1]<=' ') ls--; // search back to non-whitespace break; } if(*ls>' ') hasContent=true; // line contains something usefull } cStructItem *it=0; if(hasContent) { char save=*ls; *ls=0; it=ParseLine(skipspace(buff)); *ls=save; if(!it) { PRINTF(L_GEN_ERROR,"file %s has error in line #%d",path,lineNum); ls=buff; } else num++; } else ls=buff; if(!it) it=new cCommentItem; if(it) { it->SetComment(ls); Add(it); } else { PRINTF(L_GEN_ERROR,"out of memory loading file %s",path); SL_CLRFLAG(SL_LOADED); break; } } ListUnlock(); PRINTF(L_CORE_LOAD,"loaded %d %s from %s",num,type,path); PostLoad(); } else ListUnlock(); fclose(f); LoadFinished(); } else OpenFailed(); }
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; }
MStatus atomExport::writer( const MFileObject& file, const MString& options, FileAccessMode mode) { MStatus status = MS::kFailure; MString fileName = file.fullName(); #if defined (OSMac_) char fname[MAXPATHLEN]; strcpy (fname, fileName.asChar()); ofstream animFile(fname); #else ofstream animFile(fileName.asChar()); #endif // Defaults. // MString copyFlags("copyKey -cb api -fea 1 "); int precision = kDefaultPrecision; bool statics = false; bool includeChildren = false; std::set<std::string> attrStrings; // Parse the options. The options syntax is in the form of // "flag=val;flag1=val;flag2=val" // bool useSpecifiedRange = false; bool useTemplate = false; bool cached = false; bool constraint = false; bool sdk = false; bool animLayers = true; MString templateName; MString viewName; MTime startTime = MAnimControl::animationStartTime(); MTime endTime = MAnimControl::animationEndTime(); MString exportEditsFile; MString exportFlags; if (options.length() > 0) { const MString flagPrecision("precision"); const MString flagStatics("statics"); const MString flagConstraint("constraint"); const MString flagSDK("sdk"); const MString flagAnimLayers("animLayers"); const MString flagCopyKeyCmd("copyKeyCmd"); const MString flagSelected("selected"); const MString flagTemplate("template"); const MString flagView("view"); const MString optionChildrenToo("childrenToo"); const MString optionTemplate("template"); const MString flagAttr("at"); const MString flagWhichRange("whichRange"); const MString flagRange("range"); const MString flagExportEdits("exportEdits"); const MString flagCached("baked"); // Start parsing. // MStringArray optionList; MStringArray theOption; options.split(';', optionList); unsigned nOptions = optionList.length(); for (unsigned i = 0; i < nOptions; i++) { theOption.clear(); optionList[i].split('=', theOption); if (theOption.length() < 1) { continue; } if (theOption[0] == flagPrecision && theOption.length() > 1) { if (theOption[1].isInt()) { precision = theOption[1].asInt(); } } else if( theOption[0] == flagTemplate && theOption.length() > 1) { templateName = theOption[1]; } else if( theOption[0] == flagView && theOption.length() > 1) { viewName = theOption[1]; } else if ( theOption[0] == flagWhichRange && theOption.length() > 1) { if (theOption[1].isInt()) useSpecifiedRange = (theOption[1].asInt() ==1) ? false : true; } else if ( theOption[0] == flagRange && theOption.length() > 1) { MStringArray rangeArray; theOption[1].split(':',rangeArray); if(rangeArray.length()==2) { if(rangeArray[0].isDouble()) { double val = rangeArray[0].asDouble(); startTime = MTime(val,MTime::uiUnit()); } else if(rangeArray[0].isInt()) { double val = (double)rangeArray[0].asInt(); startTime = MTime(val,MTime::uiUnit()); } if(rangeArray[1].isDouble()) { double val = rangeArray[1].asDouble(); endTime = MTime(val,MTime::uiUnit()); } else if(rangeArray[1].isInt()) { double val = (double)rangeArray[1].asInt(); endTime = MTime(val,MTime::uiUnit()); } } } else if ( theOption[0] == flagStatics && theOption.length() > 1) { if (theOption[1].isInt()) { statics = (theOption[1].asInt()) ? true : false; } } else if ( theOption[0] == flagSDK && theOption.length() > 1) { if (theOption[1].isInt()) { sdk = (theOption[1].asInt()) ? true : false; } } else if ( theOption[0] == flagConstraint && theOption.length() > 1) { if (theOption[1].isInt()) { constraint = (theOption[1].asInt()) ? true : false; } } else if ( theOption[0] == flagAnimLayers && theOption.length() > 1) { if (theOption[1].isInt()) { animLayers = (theOption[1].asInt()) ? true : false; } } else if ( theOption[0] == flagCached && theOption.length() > 1) { if (theOption[1].isInt()) { cached = (theOption[1].asInt()) ? true : false; } } else if (theOption[0] == flagSelected && theOption.length() > 1) { includeChildren = (theOption[1] == optionChildrenToo) ? true : false; if(theOption[1] == optionTemplate) useTemplate = true; } else if (theOption[0] == flagAttr && theOption.length() > 1) { std::string str(theOption[1].asChar()); attrStrings.insert(str); } else if ( theOption[0] == flagCopyKeyCmd && theOption.length() > 1) { // Replace any '>' characters with '"'. This is needed // since the file translator option boxes do not handle // escaped quotation marks. // const char *optStr = theOption[1].asChar(); size_t nChars = strlen(optStr); char *copyStr = new char[nChars+1]; copyStr = strcpy(copyStr, optStr); for (size_t j = 0; j < nChars; j++) { if (copyStr[j] == '>') { copyStr[j] = '"'; } } copyFlags += copyStr; delete [] copyStr; } else if (theOption[0] == flagExportEdits && theOption.length() > 1) { exportEditsFile = theOption[1]; } } } // Set the precision of the ofstream. // animFile.precision(precision); atomTemplateReader templateReader; if(useTemplate == true) { includeChildren = false; templateReader.setTemplate(templateName,viewName); templateReader.selectNodes(); //make the template nodes be the selection } status = exportSelected(animFile, copyFlags, attrStrings, includeChildren, useSpecifiedRange, startTime, endTime, statics, cached,sdk,constraint, animLayers, exportEditsFile,templateReader); animFile.flush(); animFile.close(); return status; }
MTime convert( const double &from ) { return MTime( from, MTime::kSeconds ); }
PXR_NAMESPACE_OPEN_SCOPE /* static */ bool PxrUsdMayaTranslatorMesh::Create( const UsdGeomMesh& mesh, MObject parentNode, const PxrUsdMayaPrimReaderArgs& args, PxrUsdMayaPrimReaderContext* context) { if (!mesh) { return false; } const UsdPrim& prim = mesh.GetPrim(); MStatus status; // Create node (transform) MObject mayaNodeTransformObj; if (!PxrUsdMayaTranslatorUtil::CreateTransformNode(prim, parentNode, args, context, &status, &mayaNodeTransformObj)) { return false; } VtArray<GfVec3f> points; VtArray<GfVec3f> normals; VtArray<int> faceVertexCounts; VtArray<int> faceVertexIndices; UsdAttribute fvc = mesh.GetFaceVertexCountsAttr(); if (fvc.ValueMightBeTimeVarying()){ // at some point, it would be great, instead of failing, to create a usd/hydra proxy node // for the mesh, perhaps? For now, better to give a more specific error MGlobal::displayError( TfStringPrintf("<%s> is a topologically varying Mesh (animated faceVertexCounts). Skipping...", prim.GetPath().GetText()).c_str()); return false; } else { // for any non-topo-varying mesh, sampling at zero will get us the right answer fvc.Get(&faceVertexCounts, 0); } UsdAttribute fvi = mesh.GetFaceVertexIndicesAttr(); if (fvi.ValueMightBeTimeVarying()){ // at some point, it would be great, instead of failing, to create a usd/hydra proxy node // for the mesh, perhaps? For now, better to give a more specific error MGlobal::displayError( TfStringPrintf("<%s> is a topologically varying Mesh (animated faceVertexIndices). Skipping...", prim.GetPath().GetText()).c_str()); return false; } else { // for any non-topo-varying mesh, sampling at zero will get us the right answer fvi.Get(&faceVertexIndices, 0); } // Sanity Checks. If the vertex arrays are empty, skip this mesh if (faceVertexCounts.size() == 0 || faceVertexIndices.size() == 0) { MGlobal::displayError( TfStringPrintf("FaceVertex arrays are empty [Count:%zu Indices:%zu] on Mesh <%s>. Skipping...", faceVertexCounts.size(), faceVertexIndices.size(), prim.GetPath().GetText()).c_str()); return false; // invalid mesh, so exit } // Gather points and normals // If args.GetReadAnimData() is TRUE, // pick the first avaiable sample or default UsdTimeCode pointsTimeSample=UsdTimeCode::EarliestTime(); UsdTimeCode normalsTimeSample=UsdTimeCode::EarliestTime(); std::vector<double> pointsTimeSamples; size_t pointsNumTimeSamples = 0; if (args.GetReadAnimData()) { PxrUsdMayaTranslatorUtil::GetTimeSamples(mesh.GetPointsAttr(), args, &pointsTimeSamples); pointsNumTimeSamples = pointsTimeSamples.size(); if (pointsNumTimeSamples>0) { pointsTimeSample = pointsTimeSamples[0]; } std::vector<double> normalsTimeSamples; PxrUsdMayaTranslatorUtil::GetTimeSamples(mesh.GetNormalsAttr(), args, &normalsTimeSamples); if (normalsTimeSamples.size()) { normalsTimeSample = normalsTimeSamples[0]; } } mesh.GetPointsAttr().Get(&points, pointsTimeSample); mesh.GetNormalsAttr().Get(&normals, normalsTimeSample); if (points.size() == 0) { MGlobal::displayError( TfStringPrintf("Points arrays is empty on Mesh <%s>. Skipping...", prim.GetPath().GetText()).c_str()); return false; // invalid mesh, so exit } // == Convert data size_t mayaNumVertices = points.size(); MPointArray mayaPoints(mayaNumVertices); for (size_t i=0; i < mayaNumVertices; i++) { mayaPoints.set( i, points[i][0], points[i][1], points[i][2] ); } MIntArray polygonCounts( faceVertexCounts.cdata(), faceVertexCounts.size() ); MIntArray polygonConnects( faceVertexIndices.cdata(), faceVertexIndices.size() ); // == Create Mesh Shape Node MFnMesh meshFn; MObject meshObj = meshFn.create(mayaPoints.length(), polygonCounts.length(), mayaPoints, polygonCounts, polygonConnects, mayaNodeTransformObj, &status ); if (status != MS::kSuccess) { return false; } // Since we are "decollapsing", we will create a xform and a shape node for each USD prim std::string usdPrimName(prim.GetName().GetText()); std::string shapeName(usdPrimName); shapeName += "Shape"; // Set mesh name and register meshFn.setName(MString(shapeName.c_str()), false, &status); if (context) { std::string usdPrimPath(prim.GetPath().GetText()); std::string shapePath(usdPrimPath); shapePath += "/"; shapePath += shapeName; context->RegisterNewMayaNode( shapePath, meshObj ); // used for undo/redo } // If a material is bound, create (or reuse if already present) and assign it // If no binding is present, assign the mesh to the default shader const TfToken& shadingMode = args.GetShadingMode(); PxrUsdMayaTranslatorMaterial::AssignMaterial(shadingMode, mesh, meshObj, context); // Mesh is a shape, so read Gprim properties PxrUsdMayaTranslatorGprim::Read(mesh, meshObj, context); // Set normals if supplied MIntArray normalsFaceIds; if (normals.size() == static_cast<size_t>(meshFn.numFaceVertices())) { for (size_t i=0; i < polygonCounts.length(); i++) { for (int j=0; j < polygonCounts[i]; j++) { normalsFaceIds.append(i); } } if (normalsFaceIds.length() == static_cast<size_t>(meshFn.numFaceVertices())) { MVectorArray mayaNormals(normals.size()); for (size_t i=0; i < normals.size(); i++) { mayaNormals.set( MVector(normals[i][0], normals[i][1], normals[i][2]), i); } if (meshFn.setFaceVertexNormals(mayaNormals, normalsFaceIds, polygonConnects) != MS::kSuccess) { } } } // Determine if PolyMesh or SubdivMesh TfToken subdScheme = PxrUsdMayaMeshUtil::setSubdivScheme(mesh, meshFn, args.GetDefaultMeshScheme()); // If we are dealing with polys, check if there are normals // If we are dealing with SubdivMesh, read additional attributes and SubdivMesh properties if (subdScheme == UsdGeomTokens->none) { if (normals.size() == static_cast<size_t>(meshFn.numFaceVertices())) { PxrUsdMayaMeshUtil::setEmitNormals(mesh, meshFn, UsdGeomTokens->none); } } else { PxrUsdMayaMeshUtil::setSubdivInterpBoundary(mesh, meshFn, UsdGeomTokens->edgeAndCorner); PxrUsdMayaMeshUtil::setSubdivFVLinearInterpolation(mesh, meshFn); _AssignSubDivTagsToMesh(mesh, meshObj, meshFn); } // Set Holes VtArray<int> holeIndices; mesh.GetHoleIndicesAttr().Get(&holeIndices); // not animatable if ( holeIndices.size() != 0 ) { MUintArray mayaHoleIndices; mayaHoleIndices.setLength( holeIndices.size() ); for (size_t i=0; i < holeIndices.size(); i++) { mayaHoleIndices[i] = holeIndices[i]; } if (meshFn.setInvisibleFaces(mayaHoleIndices) == MS::kFailure) { MGlobal::displayError(TfStringPrintf("Unable to set Invisible Faces on <%s>", meshFn.fullPathName().asChar()).c_str()); } } // GETTING PRIMVARS std::vector<UsdGeomPrimvar> primvars = mesh.GetPrimvars(); TF_FOR_ALL(iter, primvars) { const UsdGeomPrimvar& primvar = *iter; const TfToken& name = primvar.GetBaseName(); const SdfValueTypeName& typeName = primvar.GetTypeName(); // If the primvar is called either displayColor or displayOpacity check // if it was really authored from the user. It may not have been // authored by the user, for example if it was generated by shader // values and not an authored colorset/entity. // If it was not really authored, we skip the primvar. if (name == PxrUsdMayaMeshColorSetTokens->DisplayColorColorSetName || name == PxrUsdMayaMeshColorSetTokens->DisplayOpacityColorSetName) { if (!PxrUsdMayaRoundTripUtil::IsAttributeUserAuthored(primvar)) { continue; } } // XXX: Maya stores UVs in MFloatArrays and color set data in MColors // which store floats, so we currently only import primvars holding // float-typed arrays. Should we still consider other precisions // (double, half, ...) and/or numeric types (int)? if (typeName == SdfValueTypeNames->Float2Array) { // We assume that Float2Array primvars are UV sets. if (!_AssignUVSetPrimvarToMesh(primvar, meshFn)) { MGlobal::displayWarning( TfStringPrintf("Unable to retrieve and assign data for UV set <%s> on mesh <%s>", name.GetText(), mesh.GetPrim().GetPath().GetText()).c_str()); } } else if (typeName == SdfValueTypeNames->FloatArray || typeName == SdfValueTypeNames->Float3Array || typeName == SdfValueTypeNames->Color3fArray || typeName == SdfValueTypeNames->Float4Array || typeName == SdfValueTypeNames->Color4fArray) { if (!_AssignColorSetPrimvarToMesh(mesh, primvar, meshFn)) { MGlobal::displayWarning( TfStringPrintf("Unable to retrieve and assign data for color set <%s> on mesh <%s>", name.GetText(), mesh.GetPrim().GetPath().GetText()).c_str()); } } } // We only vizualize the colorset by default if it is "displayColor". MStringArray colorSetNames; if (meshFn.getColorSetNames(colorSetNames)==MS::kSuccess) { for (unsigned int i=0; i < colorSetNames.length(); i++) { const MString colorSetName = colorSetNames[i]; if (std::string(colorSetName.asChar()) == PxrUsdMayaMeshColorSetTokens->DisplayColorColorSetName.GetString()) { MFnMesh::MColorRepresentation csRep= meshFn.getColorRepresentation(colorSetName); if (csRep==MFnMesh::kRGB || csRep==MFnMesh::kRGBA) { // both of these are needed to show the colorset. MPlug plg=meshFn.findPlug("displayColors"); if ( !plg.isNull() ) { plg.setBool(true); } meshFn.setCurrentColorSetName(colorSetName); } break; } } } // == Animate points == // Use blendShapeDeformer so that all the points for a frame are contained in a single node // if (pointsNumTimeSamples > 0) { MPointArray mayaPoints(mayaNumVertices); MObject meshAnimObj; MFnBlendShapeDeformer blendFn; MObject blendObj = blendFn.create(meshObj); if (context) { context->RegisterNewMayaNode( blendFn.name().asChar(), blendObj ); // used for undo/redo } for (unsigned int ti=0; ti < pointsNumTimeSamples; ++ti) { mesh.GetPointsAttr().Get(&points, pointsTimeSamples[ti]); for (unsigned int i=0; i < mayaNumVertices; i++) { mayaPoints.set( i, points[i][0], points[i][1], points[i][2] ); } // == Create Mesh Shape Node MFnMesh meshFn; if ( meshAnimObj.isNull() ) { meshAnimObj = meshFn.create(mayaPoints.length(), polygonCounts.length(), mayaPoints, polygonCounts, polygonConnects, mayaNodeTransformObj, &status ); if (status != MS::kSuccess) { continue; } } else { // Reuse the already created mesh by copying it and then setting the points meshAnimObj = meshFn.copy(meshAnimObj, mayaNodeTransformObj, &status); meshFn.setPoints(mayaPoints); } // Set normals if supplied // // NOTE: This normal information is not propagated through the blendShapes, only the controlPoints. // mesh.GetNormalsAttr().Get(&normals, pointsTimeSamples[ti]); if (normals.size() == static_cast<size_t>(meshFn.numFaceVertices()) && normalsFaceIds.length() == static_cast<size_t>(meshFn.numFaceVertices())) { MVectorArray mayaNormals(normals.size()); for (size_t i=0; i < normals.size(); i++) { mayaNormals.set( MVector(normals[i][0], normals[i][1], normals[i][2]), i); } if (meshFn.setFaceVertexNormals(mayaNormals, normalsFaceIds, polygonConnects) != MS::kSuccess) { } } // Add as target and set as an intermediate object blendFn.addTarget(meshObj, ti, meshAnimObj, 1.0); meshFn.setIntermediateObject(true); if (context) { context->RegisterNewMayaNode( meshFn.fullPathName().asChar(), meshAnimObj ); // used for undo/redo } } // Animate the weights so that mesh0 has a weight of 1 at frame 0, etc. MFnAnimCurve animFn; // Construct the time array to be used for all the keys MTimeArray timeArray; timeArray.setLength(pointsNumTimeSamples); for (unsigned int ti=0; ti < pointsNumTimeSamples; ++ti) { timeArray.set( MTime(pointsTimeSamples[ti]), ti); } // Key/Animate the weights MPlug plgAry = blendFn.findPlug( "weight" ); if ( !plgAry.isNull() && plgAry.isArray() ) { for (unsigned int ti=0; ti < pointsNumTimeSamples; ++ti) { MPlug plg = plgAry.elementByLogicalIndex(ti, &status); MDoubleArray valueArray(pointsNumTimeSamples, 0.0); valueArray[ti] = 1.0; // Set the time value where this mesh's weight should be 1.0 MObject animObj = animFn.create(plg, NULL, &status); animFn.addKeys(&timeArray, &valueArray); if (context) { context->RegisterNewMayaNode(animFn.name().asChar(), animObj ); // used for undo/redo } } } } return true; }
MStatus simulateBoids::doIt( const MArgList& args ) { // Description: implements the MEL boids command // Arguments: args - the argument list that was passes to the command from MEL MStatus status = MS::kSuccess; /**************************************** * building thread/dll data structure * ****************************************/ InfoCache infoCache; SimulationParameters simParams; RulesParameters *applyingRules; double progressBar=0; double aov=pi/3; int i,numberOfDesires=0; // params retrievement MSelectionList sel; MObject node; MFnDependencyNode nodeFn; MFnTransform locatorFn; MPlug plug; // simulation params int simulationLengthValue; // [int] in seconds int framesPerSecondValue; // [int] int startFrameValue; // [int] int boidsNumberValue; // [int] // export params MString logFilePathValue; // [char *] MString logFileNameValue; // [char *] int logFileTypeValue; // 0 = nCache; 1 = log file; 2 = XML; // locomotion params int locomotionModeValue; // [int] double maxSpeedValue; // [double] double maxForceValue; // [double] // double mass=1; // [double] MTime currentTime, maxTime; MPlug plugX, plugY, plugZ; double tx, ty, tz; int frameLength ; Vector * leader = NULL; MStatus leaderFound=MStatus::kFailure; MGlobal::getActiveSelectionList(sel); for ( MItSelectionList listIter(sel); !listIter.isDone(); listIter.next() ) { listIter.getDependNode(node); switch(node.apiType()) { case MFn::kTransform: // get locator transform to follow leaderFound=locatorFn.setObject(node); cout << locatorFn.name().asChar() << " is selected as locator" << endl; break; case MFn::kPluginDependNode: nodeFn.setObject(node); cout << nodeFn.name().asChar() << " is selected as brain" << endl; break; default: break; } cout<< node.apiTypeStr()<<endl; } // rules params setRuleVariables(alignment); setRuleVariables(cohesion); setRuleVariables(separation); setRuleVariables(follow); getPlugValue(simulationLength); getPlugValue(framesPerSecond); getPlugValue(startFrame); getPlugValue(boidsNumber); getPlugValue(logFileType); getRulePlugValue(alignment); getRulePlugValue(cohesion); getRulePlugValue(separation); getRulePlugValue(follow); getPlugValue(locomotionMode); getPlugValue(maxSpeed); getPlugValue(maxForce); getTypePlugValue(logFilePath); getTypePlugValue(logFileName); // counting active rules number if(alignmentActiveValue) numberOfDesires++; if(cohesionActiveValue) numberOfDesires++; if(separationActiveValue) numberOfDesires++; if(followActiveValue) numberOfDesires++; currentTime = MTime((double)startFrameValue); // MAnimControl::minTime(); maxTime = MTime((double)(startFrameValue + (simulationLengthValue * framesPerSecondValue))); // MAnimControl::maxTime(); cout << "time unit enum (6 is 24 fps): " << currentTime.unit() << endl; plugX = locatorFn.findPlug( MString( "translateX" ), &status ); plugY = locatorFn.findPlug( MString( "translateY" ), &status ); plugZ = locatorFn.findPlug( MString( "translateZ" ), &status ); frameLength = simulationLengthValue * framesPerSecondValue; if(leaderFound==MS::kSuccess) { leader = new Vector[frameLength]; while ( currentTime < maxTime ) { { int index = (int)currentTime.value() - startFrameValue; /* MGlobal::viewFrame(currentTime); pos = locatorFn.getTranslation(MSpace::kWorld); cout << "pos: " << pos.x << " " << pos.y << " " << pos.z << endl; */ status = plugX.getValue( tx, MDGContext(currentTime) ); status = plugY.getValue( ty, MDGContext(currentTime) ); status = plugZ.getValue( tz, MDGContext(currentTime) ); leader[index].x = tx; leader[index].y = ty; leader[index].z = tz; //cout << "pos at time " << currentTime.value() << " has x: " << tx << " y: " << ty << " z: " << tz << endl; currentTime++; } } } simParams.fps=framesPerSecondValue; simParams.lenght=simulationLengthValue; simParams.numberOfBoids=boidsNumberValue; simParams.maxAcceleration=maxForceValue; simParams.maxVelocity=maxSpeedValue; simParams.simplifiedLocomotion=TRUE; applyingRules=new RulesParameters[numberOfDesires]; // cache settings MString saveString; saveString = logFilePathValue+"/"+logFileNameValue; infoCache.fileName=new char[saveString.length()+1]; memcpy(infoCache.fileName,saveString.asChar(),sizeof(char)*(saveString.length()+1)); infoCache.cacheFormat=ONEFILE; infoCache.fps=framesPerSecondValue; infoCache.start=startFrameValue/framesPerSecondValue; infoCache.end=simulationLengthValue+infoCache.start; infoCache.loging=FALSE; infoCache.option=POSITIONVELOCITY; infoCache.particleSysName="BoidsNParticles"; infoCache.saveMethod=MAYANCACHE; for(i=0;i<numberOfDesires;i++) { applyingRules[i].enabled=TRUE; applyingRules[i].precedence=1; applyingRules[i].aov=aov; applyingRules[i].visibilityOption=FALSE; } if(cohesionActiveValue==0) applyingRules[COHESIONRULE].enabled=FALSE; else { applyingRules[COHESIONRULE].ruleName=COHESIONRULE; applyingRules[COHESIONRULE].ruleFactor=cohesionFactorValue; applyingRules[COHESIONRULE].ruleRadius=cohesionRadiusValue; applyingRules[COHESIONRULE].ruleWeight=cohesionWeightValue; } if(separationActiveValue==0) applyingRules[SEPARATIONRULE].enabled=FALSE; else { applyingRules[SEPARATIONRULE].ruleName=SEPARATIONRULE; applyingRules[SEPARATIONRULE].ruleFactor=separationFactorValue; applyingRules[SEPARATIONRULE].ruleRadius=separationRadiusValue; applyingRules[SEPARATIONRULE].ruleWeight=separationWeightValue; } if(alignmentActiveValue==0) applyingRules[ALIGNMENTRULE].enabled=FALSE; else { applyingRules[ALIGNMENTRULE].ruleName=ALIGNMENTRULE; applyingRules[ALIGNMENTRULE].ruleFactor=alignmentFactorValue; applyingRules[ALIGNMENTRULE].ruleRadius=alignmentRadiusValue; applyingRules[ALIGNMENTRULE].ruleWeight=alignmentWeightValue; } if(followActiveValue==0) applyingRules[FOLLOWRULE].enabled=FALSE; else { applyingRules[FOLLOWRULE].ruleName=FOLLOWRULE; applyingRules[FOLLOWRULE].ruleRadius=followRadiusValue; applyingRules[FOLLOWRULE].ruleFactor=followFactorValue; applyingRules[FOLLOWRULE].ruleWeight=followWeightValue; } // initializing simulation parameters boidInit(numberOfDesires, applyingRules, simParams , infoCache, leader); DLLData datadll; // preparing threads pool status = MThreadPool::init(); if (status==MStatus::kSuccess) { MThreadPool::newParallelRegion(ThreadsCreator, &datadll); setResult( "Command executed!\n" ); CHECK_MSTATUS(MProgressWindow::endProgress()); MThreadPool::release(); } switch(datadll.result) { case 0: status=MS::kSuccess; break; default: status=MS::kFailure; } MThreadPool::release(); return status; }
MTime convert( const float &from ) { return MTime( from, MTime::kSeconds ); }
/** * Build the animation from Maya AnimCurves */ osg::ref_ptr<osg::AnimationPath> Transform::animCurve2AnimationPath(MObject &obj) { osg::ref_ptr<osg::AnimationPath> anim = new osg::AnimationPath(); // STEP 1. Get the animation curves MFnAnimCurve tx, ty, tz, rx, ry, rz, sx, sy, sz; MFnDependencyNode dn(obj); MPlugArray conns; dn.getConnections(conns); for(int i=0; i<conns.length(); i++){ MPlug conn = conns[i]; MPlugArray connectedTo; // Get the connections having this node as destination conn.connectedTo(connectedTo, true, false); for(int j=0; j<connectedTo.length(); j++){ MPlug origin = connectedTo[j]; MObject origin_node = origin.node(); if(origin_node.hasFn(MFn::kAnimCurve)){ if(conn.name() == dn.name() + ".translateX" ){ tx.setObject(origin_node); } else if(conn.name() == dn.name() + ".translateY" ){ ty.setObject(origin_node); } else if(conn.name() == dn.name() + ".translateZ" ){ tz.setObject(origin_node); } else if(conn.name() == dn.name() + ".rotateX" ){ rx.setObject(origin_node); } else if(conn.name() == dn.name() + ".rotateY" ){ ry.setObject(origin_node); } else if(conn.name() == dn.name() + ".rotateZ" ){ rz.setObject(origin_node); } else if(conn.name() == dn.name() + ".scaleX" ){ sx.setObject(origin_node); } else if(conn.name() == dn.name() + ".scaleY" ){ sy.setObject(origin_node); } else if(conn.name() == dn.name() + ".scaleZ" ){ sz.setObject(origin_node); } else { std::cout << "Animation curve connected to parameter " << conn.name().asChar() << " (not supported)" << std::endl; } } } } // STEP 2. Build the AnimationPath from animation curves // Search the first key in time from all the AnimCurves bool t_present=false; double mint=0; #define VALID_CURVE(f) ( f.object() != MObject::kNullObj ) #define GETMIN(f) if(VALID_CURVE(f)) { \ double t = f.time(0).as(MTime::kSeconds); \ if( !t_present || t < mint ) \ mint = t; \ t_present = true; \ } GETMIN(tx); GETMIN(ty); GETMIN(tz); GETMIN(rx); GETMIN(ry); GETMIN(rz); GETMIN(sx); GETMIN(sy); GETMIN(sz); // Set the right time in Maya timeline so all properties are updated MAnimControl::setCurrentTime(MTime(mint,MTime::kSeconds)); // Create ControlPoint for initial time anim->insert(mint, osg::AnimationPath::ControlPoint( getCPPosition(obj), getCPRotation(obj), getCPScale(obj) )); double t_prev = mint; // Locate the time of the next key (in any curve) #define GET_NEXT(f) if(VALID_CURVE(f)) { \ for(int c=0; c<f.numKeys(); c++){ \ double t = f.time(c).as(MTime::kSeconds); \ if(t > t_prev && !t_present){ \ t_now = t; \ t_present = true; \ break; \ } \ else if(t > t_prev && t < t_now) { \ t_now = t; \ break; \ } \ } \ } // Get next keys cronologically double t_now = t_prev; t_present=false; GET_NEXT(tx); GET_NEXT(ty); GET_NEXT(tz); GET_NEXT(rx); GET_NEXT(ry); GET_NEXT(rz); GET_NEXT(sx); GET_NEXT(sy); GET_NEXT(sz); while(t_now != t_prev){ // Set the right time in Maya timeline so all properties are updated MAnimControl::setCurrentTime(MTime(t_now,MTime::kSeconds)); anim->insert(t_now, osg::AnimationPath::ControlPoint( getCPPosition(obj), getCPRotation(obj), getCPScale(obj) )); t_prev = t_now; t_present=false; GET_NEXT(tx); GET_NEXT(ty); GET_NEXT(tz); GET_NEXT(rx); GET_NEXT(ry); GET_NEXT(rz); GET_NEXT(sx); GET_NEXT(sy); GET_NEXT(sz); } return anim; }