void printSceneGraph(SceneNodePtr root, bool bOnlyPrintSelected) { const char* classType[]={ "FILE", "FILE_ALEMBIC", "APP", "APP_MAX", "APP_MAYA", "APP_XSI" }; const char* table[]={ "SCENE_ROOT", "NAMESPACE_TRANSFORM",//for export of XSI models "ETRANSFORM",// external transform (a parent of a geometry node) "ITRANSFORM",// internal transform (all other transforms) "CAMERA", "POLYMESH", "SUBD", "SURFACE", "CURVES", "PARTICLES", "HAIR", "LIGHT", "UNKNOWN", "NUM_NODE_TYPES" }; //ESS_LOG_WARNING("ExoSceneGraph Begin - ClassType: "<<classType[root->getClass()]); std::list<PrintStackElement> sceneStack; sceneStack.push_back(PrintStackElement(root, 0)); while( !sceneStack.empty() ) { PrintStackElement sElement = sceneStack.back(); SceneNodePtr eNode = sElement.eNode; sceneStack.pop_back(); if(!bOnlyPrintSelected || (bOnlyPrintSelected && eNode->selected)){ const char* name = eNode->name.c_str(); ESS_LOG_WARNING("Level: "<<sElement.level<<" - Name: "<<eNode->name.c_str()<<" - Type: "<<table[eNode->type]<<" - ddcID: "<<eNode->dccIdentifier.c_str()<<" - Selected: "<<(eNode->selected?"true":"false")); //if(eNode->parent){ // ESS_LOG_WARNING("Parent: "<<eNode->parent->name); //} eNode->print(); } for( std::list<SceneNodePtr>::iterator it = eNode->children.begin(); it != eNode->children.end(); it++){ sceneStack.push_back(PrintStackElement(*it, sElement.level+1)); } } ESS_LOG_WARNING("ExoSceneGraph End"); }
int createAlembicObject(AbcG::IObject &iObj, INode **pMaxNode, alembic_importoptions &options, std::string &file) { AbcA::MetaData mdata = iObj.getMetaData(); int ret = alembic_success; // if(AbcG::IXform::matches(iObj.getMetaData())) //Transform //{ // ESS_LOG_INFO( "AlembicImport_XForm: " << objects[j].getFullName() ); // int ret = AlembicImport_PolyMesh(file, iObj, options, pMaxNode); //} if (AbcG::IPolyMesh::matches(mdata) || AbcG::ISubD::matches(mdata)) { // PolyMesh / SubD ESS_LOG_INFO("AlembicImport_PolyMesh: " << iObj.getFullName()); ret = AlembicImport_PolyMesh(file, iObj, options, pMaxNode); } else if (AbcG::ICamera::matches(mdata)) { // Camera ESS_LOG_INFO("AlembicImport_Camera: " << iObj.getFullName()); ret = AlembicImport_Camera(file, iObj, options, pMaxNode); } else if (AbcG::IPoints::matches(mdata)) { // Points ESS_LOG_INFO("AlembicImport_Points: " << iObj.getFullName()); ret = AlembicImport_Points(file, iObj, options, pMaxNode); } else if (AbcG::ICurves::matches(mdata)) { // Curves if (options.loadCurvesAsNurbs) { ESS_LOG_INFO("AlembicImport_Nurbs: " << iObj.getFullName()); ret = AlembicImport_NURBS(file, iObj, options, pMaxNode); } else { ESS_LOG_INFO("AlembicImport_Shape: " << iObj.getFullName()); ret = AlembicImport_Shape(file, iObj, options, pMaxNode); } } else if (AbcG::ILight::matches(mdata)) { // Light ESS_LOG_INFO("AlembicImport_Light: " << iObj.getFullName()); ret = AlembicImport_Light(file, iObj, options, pMaxNode); } else if (AbcM::IMaterial::matches(mdata)) { ESS_LOG_WARNING( "Alembic IMaterial not yet supported: " << iObj.getFullName()); } else { // NURBS if (options.failOnUnsupported) { ESS_LOG_ERROR("Alembic data type not supported: " << iObj.getFullName()); return alembic_failure; } else { ESS_LOG_WARNING( "Alembic data type not supported: " << iObj.getFullName()); } } return ret; }
void AbcNodeUtils::printCompoundProperty( Abc::ICompoundProperty prop ) { if(!prop){ return; } for(size_t i=0; i<prop.getNumProperties(); i++){ AbcA::PropertyHeader pheader = prop.getPropertyHeader(i); AbcA::PropertyType propType = pheader.getPropertyType(); ESS_LOG_WARNING("PropertyType: "<<AbcNodeUtils::getTypeStr(propType)); ESS_LOG_WARNING("PropertyName: "<<pheader.getName()<<", pod: "<<AbcNodeUtils::getPodStr(pheader.getDataType().getPod()) \ <<", extent: "<<(int)pheader.getDataType().getExtent()<<", interpretation: "<<pheader.getMetaData().get("interpretation")); } }
int ExocortexAlembicStaticInterface::ExocortexMemoryDiagnostics() { ESS_LOG_WARNING( "Exocortex Memory Diagnostics -----------------------------------------------------" ); #ifdef _DEBUG //Exocortex::essLogActiveAllocations(); #endif return 0; }
Abc::ICompoundProperty getArbGeomParams(const AbcG::IObject& iObj, AbcA::TimeSamplingPtr& timeSampling, int& nSamples) { if (AbcG::IXform::matches(iObj.getMetaData())) { AbcG::IXform obj(iObj, Abc::kWrapExisting); timeSampling = obj.getSchema().getTimeSampling(); nSamples = (int)obj.getSchema().getNumSamples(); return obj.getSchema().getArbGeomParams(); } else if (AbcG::IPolyMesh::matches(iObj.getMetaData())) { AbcG::IPolyMesh obj(iObj, Abc::kWrapExisting); timeSampling = obj.getSchema().getTimeSampling(); nSamples = (int)obj.getSchema().getNumSamples(); return obj.getSchema().getArbGeomParams(); } else if (AbcG::ISubD::matches(iObj.getMetaData())) { AbcG::ISubD obj(iObj, Abc::kWrapExisting); timeSampling = obj.getSchema().getTimeSampling(); nSamples = (int)obj.getSchema().getNumSamples(); return obj.getSchema().getArbGeomParams(); } else if (AbcG::ICamera::matches(iObj.getMetaData())) { AbcG::ICamera obj(iObj, Abc::kWrapExisting); timeSampling = obj.getSchema().getTimeSampling(); nSamples = (int)obj.getSchema().getNumSamples(); return obj.getSchema().getArbGeomParams(); } else if (AbcG::IPoints::matches(iObj.getMetaData())) { AbcG::IPoints obj(iObj, Abc::kWrapExisting); timeSampling = obj.getSchema().getTimeSampling(); nSamples = (int)obj.getSchema().getNumSamples(); return obj.getSchema().getArbGeomParams(); } else if (AbcG::ICurves::matches(iObj.getMetaData())) { AbcG::ICurves obj(iObj, Abc::kWrapExisting); timeSampling = obj.getSchema().getTimeSampling(); nSamples = (int)obj.getSchema().getNumSamples(); return obj.getSchema().getArbGeomParams(); } else if (AbcG::ILight::matches(iObj.getMetaData())) { AbcG::ILight obj(iObj, Abc::kWrapExisting); timeSampling = obj.getSchema().getTimeSampling(); nSamples = (int)obj.getSchema().getNumSamples(); return obj.getSchema().getArbGeomParams(); } else if (AbcG::INuPatch::matches(iObj.getMetaData())) { AbcG::INuPatch obj(iObj, Abc::kWrapExisting); timeSampling = obj.getSchema().getTimeSampling(); nSamples = (int)obj.getSchema().getNumSamples(); return obj.getSchema().getArbGeomParams(); } else { ESS_LOG_WARNING("Could not read ArgGeomParams from " << iObj.getFullName()); return Abc::ICompoundProperty(); } }
string readEnvVar(const string &str) { const char *env_value = getenv(str.c_str()); if (!env_value) { ESS_LOG_WARNING("Environment variable \"" << str << "\" is invalid and is not replaced"); return str; } return std::string(env_value); }
std::string getUniqueName(const std::string& parentFullName, std::string& name, bool bValidate, bool& bRenamed) { std::string identifier = parentFullName; identifier += "/"; identifier += name; // ESS_LOG_WARNING("lookup: "<<identifier); identifierCountMap::iterator it = identifierCount.find(identifier); if (it == identifierCount.end()) { identifierCount[identifier] = 0; return name; } else { identifierCount[identifier] = it->second + 1; std::string fixedName = removeXfoSuffix(name); std::stringstream stream; stream << fixedName << "_" << it->second; if (fixedName.size() != name.size()) { // for Maya compatibility stream << "Xfo"; } bRenamed = true; if (!bValidate) { ESS_LOG_WARNING("Renaming " << name << " to " << stream.str()); } else { ESS_LOG_WARNING("A sibling node named " << name << " already exists."); } return stream.str(); } }
Abc::ICompoundProperty AbcNodeUtils::getUserProperties( const AbcG::IObject& iObj) { if (AbcG::IXform::matches(iObj.getMetaData())) { AbcG::IXform obj(iObj, Abc::kWrapExisting); return obj.getSchema().getUserProperties(); } else if (AbcG::IPolyMesh::matches(iObj.getMetaData())) { AbcG::IPolyMesh obj(iObj, Abc::kWrapExisting); return obj.getSchema().getUserProperties(); } else if (AbcG::ISubD::matches(iObj.getMetaData())) { AbcG::ISubD obj(iObj, Abc::kWrapExisting); return obj.getSchema().getUserProperties(); } else if (AbcG::ICamera::matches(iObj.getMetaData())) { AbcG::ICamera obj(iObj, Abc::kWrapExisting); return obj.getSchema().getUserProperties(); } else if (AbcG::IPoints::matches(iObj.getMetaData())) { AbcG::IPoints obj(iObj, Abc::kWrapExisting); return obj.getSchema().getUserProperties(); } else if (AbcG::ICurves::matches(iObj.getMetaData())) { AbcG::ICurves obj(iObj, Abc::kWrapExisting); return obj.getSchema().getUserProperties(); } else if (AbcG::ILight::matches(iObj.getMetaData())) { AbcG::ILight obj(iObj, Abc::kWrapExisting); return obj.getSchema().getUserProperties(); } else if (AbcG::INuPatch::matches(iObj.getMetaData())) { AbcG::INuPatch obj(iObj, Abc::kWrapExisting); return obj.getSchema().getUserProperties(); } else { ESS_LOG_WARNING("Could not read ArgGeomParams from " << iObj.getFullName()); return Abc::ICompoundProperty(); } }
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; }
void SceneNodeAlembic::print() { ESS_LOG_WARNING("AlembicNodeObjectFullName: "<<pObjCache->obj.getFullName()); }
int AlembicImport_Light(const std::string &path, AbcG::IObject& iObj, alembic_importoptions &options, INode** pMaxNode) { //#define OMNI_LIGHT_CLASS_ID 0x1011 //#define SPOT_LIGHT_CLASS_ID 0x1012 //#define DIR_LIGHT_CLASS_ID 0x1013 //#define FSPOT_LIGHT_CLASS_ID 0x1014 //#define TDIR_LIGHT_CLASS_ID 0x1015 //#define OMNI_LIGHT 0 // Omnidirectional //#define TSPOT_LIGHT 1 // Targeted //#define DIR_LIGHT 2 // Directional //#define FSPOT_LIGHT 3 // Free //#define TDIR_LIGHT 4 // Targeted directional if(options.attachToExisting){ ESS_LOG_WARNING("Attach to existing for lights is not yet supported. Could not attach "<<iObj.getFullName()); return alembic_success; } std::vector<matShader> shaders; AbcG::ILight objLight = AbcG::ILight(iObj, Alembic::Abc::kWrapExisting); std::string identifier = objLight.getFullName(); //CompoundPropertyReaderPtr propReader = objLight.getProperties(); Abc::ICompoundProperty props = objLight.getProperties(); InputLightType::enumt lightType = InputLightType::NUM_INPUT_LIGHT_TYPES; for(int i=0; i<props.getNumProperties(); i++){ Abc::PropertyHeader propHeader = props.getPropertyHeader(i); if(AbcM::IMaterialSchema::matches(propHeader)){ AbcM::IMaterialSchema matSchema(props, propHeader.getName()); //ESS_LOG_WARNING("MaterialSchema present on light."); lightType = readShader(matSchema, shaders); } //ESS_LOG_WARNING("name: "<<propHeader.getName()); //if( AbcG::ICameraSchema::matches(propHeader) ){ // ESS_LOG_WARNING("Found light camera."); // //AbcG::ICameraSchema camSchema(props, propHeader.getName()); //} } bool bReplaceExisting = false; int nodeRes = alembic_failure; if(lightType == InputLightType::AMBIENT_LIGHT){ nodeRes = createNode(iObj, LIGHT_CLASS_ID, Class_ID(OMNI_LIGHT_CLASS_ID, 0), pMaxNode, bReplaceExisting); //Modifier* pModifier = FindModifier(*pMaxNode, Class_ID(OMNI_LIGHT_CLASS_ID, 0)); //if(pModifier){ // ESS_LOG_WARNING("NumParamBlocks: "<<pModifier->NumParamBlocks()); //} //printControllers(*pMaxNode); //pMaxNode>GetParamBlockByID( 0 )->SetValue( GetParamIdByName( pModifier, 0, "muted" ), zero, FALSE ); GET_MAX_INTERFACE()->SelectNode(*pMaxNode); //set the ambient check box, intensity controller, and light colour controller (not sure how to this in C++) std::stringstream evalStream; std::string modkey(""); for(int s=0; s<shaders.size(); s++){ std::string target = shaders[s].target; std::string type = shaders[s].type; for(int i=0; i<shaders[s].props.size(); i++){ std::string propName = shaders[s].props[i].name; std::string& val = shaders[s].props[i].displayVal; bool& bConstant = shaders[s].props[i].bConstant; const AbcA::DataType& datatype = shaders[s].props[i].propHeader.getDataType(); const AbcA::MetaData& metadata = shaders[s].props[i].propHeader.getMetaData(); if(datatype.getPod() == AbcA::kFloat32POD){ std::stringstream propStream; propStream<<target<<"."<<type<<"."<<propName; if(datatype.getExtent() == 1 && propName.find("intensity") != std::string::npos ){ //intensity property found, so attach controller addFloatController(evalStream, options, modkey, std::string("multiplier"), path, iObj.getFullName(), propStream.str()); } else if(datatype.getExtent() == 3 && propName.find("lightcolor") != std::string::npos ){ //color property found, so attach controller std::stringstream xStream, yStream, zStream; xStream<<propStream.str()<<"."<<metadata.get("interpretation")<<".x"; yStream<<propStream.str()<<"."<<metadata.get("interpretation")<<".y"; zStream<<propStream.str()<<"."<<metadata.get("interpretation")<<".z"; evalStream<<"$.rgb.controller = Color_RGB()\n"; addFloatController(evalStream, options, modkey, std::string("rgb.controller.r"), path, iObj.getFullName(), xStream.str()); addFloatController(evalStream, options, modkey, std::string("rgb.controller.g"), path, iObj.getFullName(), yStream.str()); addFloatController(evalStream, options, modkey, std::string("rgb.controller.b"), path, iObj.getFullName(), zStream.str()); } } else{ } evalStream<<"\n"; } } evalStream<<"$.ambientOnly = true\n"; ExecuteMAXScriptScript( EC_UTF8_to_TCHAR((char*)evalStream.str().c_str())); } else{//create a null, if we don't know what type of light this is nodeRes = createNode(iObj, HELPER_CLASS_ID, Class_ID(DUMMY_CLASS_ID,0), pMaxNode, bReplaceExisting); } if(nodeRes == alembic_failure){ return nodeRes; } GET_MAX_INTERFACE()->SelectNode(*pMaxNode); for(int i=0; i<shaders.size(); i++){ std::sort(shaders[i].props.begin(), shaders[i].props.end(), sortFunc); Modifier* pMod = createDisplayModifier("Shader Properties", shaders[i].name, shaders[i].props); std::string target = shaders[i].target; std::string type = shaders[i].type; addControllersToModifier("Shader Properties", shaders[i].name, shaders[i].props, target, type, path, iObj.getFullName(), options); } // ----- TODO: add camera modifier //createCameraModifier(path, identifier, *pMaxNode); // ----- TODO: don't attach controllers for constant parameters //TODO: make the spinners read only return alembic_success; }
//TODO: out at maximum one warning per unsupported type void readInputProperties( Abc::ICompoundProperty prop, std::vector<AbcProp>& props ) { if(!prop){ return; } for(size_t i=0; i<prop.getNumProperties(); i++){ AbcA::PropertyHeader pheader = prop.getPropertyHeader(i); AbcA::PropertyType propType = pheader.getPropertyType(); //ESS_LOG_WARNING("Property, propName: "<<pheader.getName()<<", pod: "<<getPodStr(pheader.getDataType().getPod()) \ // <<", extent: "<<(int)pheader.getDataType().getExtent()<<", interpretation: "<<pheader.getMetaData().get("interpretation")); int invalidStrIndex = containsInvalidString(pheader.getName()); if( invalidStrIndex > 0 ){ ESS_LOG_WARNING("Skipping property "<<pheader.getName()<<" because it contains an invalid character: "<<invalidStrTable[invalidStrIndex]); continue; } if( propType == AbcA::kCompoundProperty ){ //printInputProperties(Abc::ICompoundProperty(prop, pheader.getName())); //ESS_LOG_WARNING("Unsupported compound property: "<<pheader.getName()); } else if( propType == AbcA::kScalarProperty ){ //ESS_LOG_WARNING("Scaler property: "<<pheader.getName()); // std::string displayVal; bool bConstant = true; int sortId = 0; int size = 0; if(Abc::IBoolProperty::matches(pheader)){ //I need to know the name and type only if animated; an appropriate controller will handle reading the data. //If not animated, the value will set directly on the light and/or display modifier Abc::IBoolProperty boolProp(prop, pheader.getName()); /*if(boolProp.isConstant()){*/ AbcU::bool_t bVal = false; boolProp.get(bVal); if(bVal == true) displayVal = "true"; else displayVal = "false"; //} //else{ // //} } else if(readPropExt1<Abc::IInt32Property, int>(prop, pheader, displayVal, bConstant)); else if(readPropExt1<Abc::IFloatProperty, float>(prop, pheader, displayVal, bConstant)); else if(readPropExt3<Abc::IC3fProperty, Abc::C3f>(prop, pheader, displayVal, bConstant)); else if(readPropExt3<Abc::IV3fProperty, Abc::V3f>(prop, pheader, displayVal, bConstant)); else if(readPropExt3<Abc::IN3fProperty, Abc::N3f>(prop, pheader, displayVal, bConstant)); else if(Abc::IStringProperty::matches(pheader)){ Abc::IStringProperty stringProp(prop, pheader.getName()); stringProp.get(displayVal); sortId = 1000000000; } else{ // Abc::PropertyHeader propHeader = props.getPropertyHeader(i); // AbcA::PropertyType propType = propHeader.getPropertyType(); ESS_LOG_WARNING("Unsupported property, propName: "<<pheader.getName()<<", pod: "<<getPodStr(pheader.getDataType().getPod()) \ <<", extent: "<<(int)pheader.getDataType().getExtent()<<", interpretation: "<<pheader.getMetaData().get("interpretation")); } props.push_back(AbcProp(pheader.getName(), displayVal, pheader, bConstant, sortId)); } else if( propType == AbcA::kArrayProperty ){ //ESS_LOG_WARNING("Unsupported array property: "<<pheader.getName()); //it the moment is unlikely we will support array properties in 3DS Max. They won't work so well with our display modifier system. //ESS_LOG_WARNING("Unsupported array property, propName: "<<pheader.getName()<<", pod: "<<getPodStr(pheader.getDataType().getPod()) \ //<<", extent: "<<(int)pheader.getDataType().getExtent()<<", interpretation: "<<pheader.getMetaData().get("interpretation")); } else{ ESS_LOG_WARNING("Unsupported input property: "<<pheader.getName()); } } }
bool AlembicCurves::Save(double time, bool bLastFrame) { ESS_PROFILE_FUNC(); //TimeValue ticks = GET_MAX_INTERFACE()->GetTime(); TimeValue ticks = GetTimeValueFromFrame(time); Object *obj = mMaxNode->EvalWorldState(ticks).obj; if(mNumSamples == 0){ bForever = CheckIfObjIsValidForever(obj, ticks); } else{ bool bNewForever = CheckIfObjIsValidForever(obj, ticks); if(bForever && bNewForever != bForever){ ESS_LOG_INFO( "bForever has changed" ); } } SaveMetaData(mMaxNode, this); // check if the spline is animated if(mNumSamples > 0) { if(bForever) { return true; } } AbcG::OCurvesSchema::Sample curvesSample; std::vector<AbcA::int32_t> nbVertices; std::vector<Point3> vertices; std::vector<float> knotVector; std::vector<Abc::uint16_t> orders; if(obj->ClassID() == EDITABLE_SURF_CLASS_ID){ NURBSSet nurbsSet; BOOL success = GetNURBSSet(obj, ticks, nurbsSet, TRUE); AbcG::CurvePeriodicity cPeriod = AbcG::kNonPeriodic; AbcG::CurveType cType = AbcG::kCubic; AbcG::BasisType cBasis = AbcG::kNoBasis; int n = nurbsSet.GetNumObjects(); for(int i=0; i<n; i++){ NURBSObject* pObject = nurbsSet.GetNURBSObject((int)i); //NURBSType type = pObject->GetType(); if(!pObject){ continue; } if( pObject->GetKind() == kNURBSCurve ){ NURBSCurve* pNurbsCurve = (NURBSCurve*)pObject; int degree; int numCVs; NURBSCVTab cvs; int numKnots; NURBSKnotTab knots; pNurbsCurve->GetNURBSData(ticks, degree, numCVs, cvs, numKnots, knots); orders.push_back(degree+1); const int cvsCount = cvs.Count(); const int knotCount = knots.Count(); for(int j=0; j<cvs.Count(); j++){ NURBSControlVertex cv = cvs[j]; double x, y, z; cv.GetPosition(ticks, x, y, z); vertices.push_back( Point3((float)x, (float)y, (float)z) ); } nbVertices.push_back(cvsCount); //skip the first and last entry because Maya and XSI use this format for(int j=1; j<knots.Count()-1; j++){ knotVector.push_back((float)knots[j]); } if(i == 0){ if(pNurbsCurve->IsClosed()){ cPeriod = AbcG::kPeriodic; } } else{ if(pNurbsCurve->IsClosed()){ if(cPeriod != AbcG::kPeriodic){ ESS_LOG_WARNING("Mixed curve wrap types not supported."); } } else{ if(cPeriod != AbcG::kNonPeriodic){ ESS_LOG_WARNING("Mixed curve wrap types not supported."); } } } } } curvesSample.setType(cType); curvesSample.setWrap(cPeriod); curvesSample.setBasis(cBasis); } else { BezierShape beziershape; PolyShape polyShape; bool bBezier = false; // Get a pointer to the spline shpae ShapeObject *pShapeObject = NULL; if (obj->IsShapeObject()) { pShapeObject = reinterpret_cast<ShapeObject *>(obj); } else { return false; } // Determine if we are a bezier shape if (pShapeObject->CanMakeBezier()) { pShapeObject->MakeBezier(ticks, beziershape); bBezier = true; } else { pShapeObject->MakePolyShape(ticks, polyShape); bBezier = false; } // Get the control points //std::vector<Point3> inTangents; //std::vector<Point3> outTangents; if (bBezier) { int oldVerticesCount = (int)vertices.size(); for (int i = 0; i < beziershape.SplineCount(); i += 1) { Spline3D *pSpline = beziershape.GetSpline(i); int knots = pSpline->KnotCount(); for(int ix = 0; ix < knots; ++ix) { Point3 in = pSpline->GetInVec(ix); Point3 p = pSpline->GetKnotPoint(ix); Point3 out = pSpline->GetOutVec(ix); vertices.push_back( p ); //inTangents.push_back( in ); //outTangents.push_back( out ); } int nNumVerticesAdded = (int)vertices.size() - oldVerticesCount; nbVertices.push_back( nNumVerticesAdded ); oldVerticesCount = (int)vertices.size(); } } else { for (int i = 0; i < polyShape.numLines; i += 1) { PolyLine &refLine = polyShape.lines[i]; nbVertices.push_back(refLine.numPts); for (int j = 0; j < refLine.numPts; j += 1) { Point3 p = refLine.pts[j].p; vertices.push_back(p); } } } // set the type + wrapping curvesSample.setType(bBezier ? AbcG::kCubic : AbcG::kLinear); curvesSample.setWrap(pShapeObject->CurveClosed(ticks, 0) ? AbcG::kPeriodic : AbcG::kNonPeriodic); curvesSample.setBasis(AbcG::kNoBasis); } if(nbVertices.size() == 0 || vertices.size() == 0){ ESS_LOG_WARNING("No curve data to export."); return false; } const int vertCount = (int)vertices.size(); // prepare the bounding box Abc::Box3d bbox; // allocate the points and normals std::vector<Abc::V3f> posVec(vertCount); Matrix3 wm = mMaxNode->GetObjTMAfterWSM(ticks); for(int i=0;i<vertCount;i++) { posVec[i] = ConvertMaxPointToAlembicPoint(vertices[i] ); bbox.extendBy(posVec[i]); // Set the archive bounding box if (mJob) { Point3 worldMaxPoint = wm * vertices[i]; Abc::V3f alembicWorldPoint = ConvertMaxPointToAlembicPoint(worldMaxPoint); mJob->GetArchiveBBox().extendBy(alembicWorldPoint); } } if(knotVector.size() > 0 && orders.size() > 0){ if(!mKnotVectorProperty.valid()){ mKnotVectorProperty = Abc::OFloatArrayProperty(mCurvesSchema.getArbGeomParams(), ".knot_vector", mCurvesSchema.getMetaData(), mJob->GetAnimatedTs() ); } mKnotVectorProperty.set(Abc::FloatArraySample(knotVector)); if(!mOrdersProperty.valid()){ mOrdersProperty = Abc::OUInt16ArrayProperty(mCurvesSchema.getArbGeomParams(), ".orders", mCurvesSchema.getMetaData(), mJob->GetAnimatedTs() ); } mOrdersProperty.set(Abc::UInt16ArraySample(orders)); } // store the bbox curvesSample.setSelfBounds(bbox); mCurvesSchema.getChildBoundsProperty().set(bbox); Abc::Int32ArraySample nbVerticesSample(&nbVertices.front(),nbVertices.size()); curvesSample.setCurvesNumVertices(nbVerticesSample); // allocate for the points and normals Abc::P3fArraySample posSample(&posVec.front(),posVec.size()); curvesSample.setPositions(posSample); mCurvesSchema.set(curvesSample); mNumSamples++; return true; }
void AlembicFloatController::GetValueLocalTime(TimeValue t, void* ptr, Interval& valid, GetSetMethod method) { ESS_CPP_EXCEPTION_REPORTING_START Interval interval = FOREVER; MCHAR const* strPath = NULL; this->pblock->GetValue(AlembicFloatController::ID_PATH, t, strPath, interval); MCHAR const* strIdentifier = NULL; this->pblock->GetValue(AlembicFloatController::ID_IDENTIFIER, t, strIdentifier, interval); MCHAR const* strCategory = NULL; this->pblock->GetValue(AlembicFloatController::ID_CATEGORY, t, strCategory, interval); MCHAR const* strProperty = NULL; this->pblock->GetValue(AlembicFloatController::ID_PROPERTY, t, strProperty, interval); float fTime; this->pblock->GetValue(AlembicFloatController::ID_TIME, t, fTime, interval); BOOL bMuted; this->pblock->GetValue(AlembicFloatController::ID_MUTED, t, bMuted, interval); extern bool g_bVerboseLogging; if (g_bVerboseLogging) { ESS_LOG_WARNING("Param block at tick " << t << "-----------------------"); ESS_LOG_WARNING("PATH: " << strPath); ESS_LOG_WARNING("IDENTIFIER: " << strIdentifier); ESS_LOG_WARNING("PROPERTY: " << strProperty); ESS_LOG_WARNING("TIME: " << fTime); ESS_LOG_WARNING("MUTED: " << bMuted); ESS_LOG_WARNING("Param block end -------------"); } const float fDefaultVal = -1.0; std::string szPath = EC_MCHAR_to_UTF8(strPath); std::string szIdentifier = EC_MCHAR_to_UTF8(strIdentifier); std::string szProperty = EC_MCHAR_to_UTF8(strProperty); std::string szCategory = EC_MCHAR_to_UTF8(strCategory); if (szCategory.empty()) { // default to standard properties for backwards // compatibility szCategory = std::string("standardProperties"); } if (!strProperty || !strPath || !strIdentifier /*|| !strCategory*/) { return setController("1", szProperty, valid, interval, method, ptr, fDefaultVal); } if (bMuted) { return setController("2", szProperty, valid, interval, method, ptr, fDefaultVal); } // if( szCategory.size() == 0 ) { // ESS_LOG_ERROR( "No category specified." ); // return setController("3a", szProperty, valid, interval, method, ptr, // fDefaultVal); //} if (szProperty.size() == 0) { ESS_LOG_ERROR("No property specified."); return setController("3b", szProperty, valid, interval, method, ptr, fDefaultVal); } AbcG::IObject iObj = getObjectFromArchive(szPath, szIdentifier); if (!iObj.valid()) { return setController("4", szProperty, valid, interval, method, ptr, fDefaultVal); } TimeValue dTicks = GetTimeValueFromSeconds(fTime); double sampleTime = GetSecondsFromTimeValue(dTicks); float fSampleVal = fDefaultVal; if (boost::iequals(szCategory, "standardProperties")) { if (Alembic::AbcGeom::ICamera::matches( iObj.getMetaData())) { // standard camera properties Alembic::AbcGeom::ICamera objCamera = Alembic::AbcGeom::ICamera(iObj, Alembic::Abc::kWrapExisting); SampleInfo sampleInfo = getSampleInfo(sampleTime, objCamera.getSchema().getTimeSampling(), objCamera.getSchema().getNumSamples()); Alembic::AbcGeom::CameraSample sample; objCamera.getSchema().get(sample, sampleInfo.floorIndex); double sampleVal; if (!getCameraSampleVal(objCamera, sampleInfo, sample, szProperty, sampleVal)) { return setController("5", szProperty, valid, interval, method, ptr, fDefaultVal); } // Blend the camera values, if necessary if (sampleInfo.alpha != 0.0) { objCamera.getSchema().get(sample, sampleInfo.ceilIndex); double sampleVal2 = 0.0; if (getCameraSampleVal(objCamera, sampleInfo, sample, szProperty, sampleVal2)) { sampleVal = (1.0 - sampleInfo.alpha) * sampleVal + sampleInfo.alpha * sampleVal2; } } fSampleVal = (float)sampleVal; } else if (Alembic::AbcGeom::ILight::matches( iObj.getMetaData())) { // ILight material properties ESS_PROFILE_SCOPE( "AlembicFloatController::GetValueLocalTime - read ILight shader " "parameter"); Alembic::AbcGeom::ILight objLight = Alembic::AbcGeom::ILight(iObj, Alembic::Abc::kWrapExisting); SampleInfo sampleInfo = getSampleInfo(sampleTime, objLight.getSchema().getTimeSampling(), objLight.getSchema().getNumSamples()); AbcM::IMaterialSchema matSchema = getMatSchema(objLight); std::string strProp = szProperty; std::vector<std::string> parts; boost::split(parts, strProp, boost::is_any_of(".")); if (parts.size() == 3) { const std::string& target = parts[0]; const std::string& type = parts[1]; const std::string& prop = parts[2]; Abc::IFloatProperty fProp = readShaderScalerProp<Abc::IFloatProperty>( matSchema, target, type, prop); if (fProp.valid()) { fProp.get(fSampleVal, sampleInfo.floorIndex); } else { ESS_LOG_WARNING("Float Controller Error: could find shader parameter " << strProp); } } else if (parts.size() == 5) { const std::string& target = parts[0]; const std::string& type = parts[1]; const std::string& prop = parts[2]; const std::string& propInterp = parts[3]; const std::string& propComp = parts[4]; // ESS_LOG_WARNING("propInterp: "<<propInterp); if (propInterp == "rgb") { Abc::IC3fProperty fProp = readShaderScalerProp<Abc::IC3fProperty>( matSchema, target, type, prop); if (fProp.valid()) { Abc::C3f v3f; fProp.get(v3f, sampleInfo.floorIndex); if (propComp == "x") { fSampleVal = v3f.x; } else if (propComp == "y") { fSampleVal = v3f.y; } else if (propComp == "z") { fSampleVal = v3f.z; } else { ESS_LOG_WARNING( "Float Controller Error: invalid component: " << propComp); } } else { ESS_LOG_WARNING( "Float Controller Error: could find shader parameter " << strProp); } } else { ESS_LOG_WARNING( "Float Controller Error: unrecognized parameter interpretation: " << propInterp); } } else { ESS_LOG_WARNING( "Float Controller Error: could not parse property field: " << strProperty); } } } else if (boost::iequals(szCategory, "userProperties")) { // AbcA::TimeSamplingPtr timeSampling = obj.getSchema().getTimeSampling(); // int nSamples = (int)obj.getSchema().getNumSamples(); AbcA::TimeSamplingPtr timeSampling; int nSamples = 0; Abc::ICompoundProperty propk = AbcNodeUtils::getUserProperties(iObj, timeSampling, nSamples); if (propk.valid()) { SampleInfo sampleInfo = getSampleInfo(sampleTime, timeSampling, nSamples); std::vector<std::string> parts; boost::split(parts, szProperty, boost::is_any_of(".")); if (parts.size() == 1) { Abc::IFloatProperty fProp = readScalarProperty<Abc::IFloatProperty>(propk, szProperty); if (fProp.valid()) { fProp.get(fSampleVal, sampleInfo.floorIndex); } else { Abc::IInt32Property intProp = readScalarProperty<Abc::IInt32Property>(propk, szProperty); if (intProp.valid()) { int intVal; intProp.get(intVal, sampleInfo.floorIndex); fSampleVal = (float)intVal; } else { ESS_LOG_WARNING( "Float Controller Error: could not read user property " << szProperty); } } } else if (parts.size() == 3) { const std::string& prop = parts[0]; const std::string& propInterp = parts[1]; const std::string& propComp = parts[2]; // ESS_LOG_WARNING("interpretation: "<<propInterp); if (propInterp == "rgb") { fSampleVal = readScalarPropertyExt3<Abc::IC3fProperty, Abc::C3f>( propk, sampleInfo, prop, propComp); } else if (propInterp == "vector") { fSampleVal = readScalarPropertyExt3<Abc::IV3fProperty, Abc::V3f>( propk, sampleInfo, prop, propComp); } else { ESS_LOG_WARNING( "Float Controller Error: unrecognized parameter interpretation: " << propInterp); } } } } // else if( boost::iequals(szCategory, "arbGeomParams") ){ //} return setController("6", szProperty, valid, interval, method, ptr, fSampleVal); ESS_CPP_EXCEPTION_REPORTING_END }
bool AlembicPoints::Save(double time, bool bLastFrame) { ESS_PROFILE_FUNC(); // Note: Particles are always considered to be animated even though // the node does not have the IsAnimated() flag. // Extract our particle emitter at the given time TimeValue ticks = GetTimeValueFromFrame(time); Object *obj = mMaxNode->EvalWorldState(ticks).obj; SaveMetaData(mMaxNode, this); SimpleParticle* pSimpleParticle = (SimpleParticle*)obj->GetInterface(I_SIMPLEPARTICLEOBJ); IPFSystem* ipfSystem = GetPFSystemInterface(obj); IParticleObjectExt* particlesExt = GetParticleObjectExtInterface(obj); #ifdef THINKING_PARTICLES ParticleMat* pThinkingParticleMat = NULL; TP_MasterSystemInterface* pTPMasterSystemInt = NULL; if(obj->CanConvertToType(MATTERWAVES_CLASS_ID)) { pThinkingParticleMat = reinterpret_cast<ParticleMat*>(obj->ConvertToType(ticks, MATTERWAVES_CLASS_ID)); pTPMasterSystemInt = reinterpret_cast<TP_MasterSystemInterface*>(obj->GetInterface(IID_TP_MASTERSYSTEM)); } #endif const bool bAutomaticInstancing = GetCurrentJob()->GetOption("automaticInstancing"); if( #ifdef THINKING_PARTICLES !pThinkingParticleMat && #endif !particlesExt && !pSimpleParticle){ return false; } //We have to put the particle system into the renders state so that PFOperatorMaterialFrequency::Proceed will set the materialID channel //Note: settting the render state to true breaks the shape node instancing export bool bRenderStateForced = false; if(bAutomaticInstancing && ipfSystem && !ipfSystem->IsRenderState()){ ipfSystem->SetRenderState(true); bRenderStateForced = true; } int numParticles = 0; #ifdef THINKING_PARTICLES if(pThinkingParticleMat){ numParticles = pThinkingParticleMat->NumParticles(); } else #endif if(particlesExt){ particlesExt->UpdateParticles(mMaxNode, ticks); numParticles = particlesExt->NumParticles(); } else if(pSimpleParticle){ pSimpleParticle->Update(ticks, mMaxNode); numParticles = pSimpleParticle->parts.points.Count(); } // Store positions, velocity, width/size, scale, id, bounding box std::vector<Abc::V3f> positionVec; std::vector<Abc::V3f> velocityVec; std::vector<Abc::V3f> scaleVec; std::vector<float> widthVec; std::vector<float> ageVec; std::vector<float> massVec; std::vector<float> shapeTimeVec; std::vector<Abc::uint64_t> idVec; std::vector<Abc::uint16_t> shapeTypeVec; std::vector<Abc::uint16_t> shapeInstanceIDVec; std::vector<Abc::Quatf> orientationVec; std::vector<Abc::Quatf> angularVelocityVec; std::vector<Abc::C4f> colorVec; positionVec.reserve(numParticles); velocityVec.reserve(numParticles); scaleVec.reserve(numParticles); widthVec.reserve(numParticles); ageVec.reserve(numParticles); massVec.reserve(numParticles); shapeTimeVec.reserve(numParticles); idVec.reserve(numParticles); shapeTypeVec.reserve(numParticles); shapeInstanceIDVec.reserve(numParticles); orientationVec.reserve(numParticles); angularVelocityVec.reserve(numParticles); colorVec.reserve(numParticles); //std::vector<std::string> instanceNamesVec; Abc::Box3d bbox; bool constantPos = true; bool constantVel = true; bool constantScale = true; bool constantWidth = true; bool constantAge = true; bool constantOrientation = true; bool constantAngularVel = true; bool constantColor = true; if(bAutomaticInstancing){ SetMaxSceneTime(ticks); } //The MAX interfaces return everything in world coordinates, //so we need to multiply the inverse the node world transform matrix Matrix3 nodeWorldTM = mMaxNode->GetObjTMAfterWSM(ticks); // Convert the max transform to alembic Matrix3 alembicMatrix; ConvertMaxMatrixToAlembicMatrix(nodeWorldTM, alembicMatrix); Abc::M44d nodeWorldTrans( alembicMatrix.GetRow(0).x, alembicMatrix.GetRow(0).y, alembicMatrix.GetRow(0).z, 0, alembicMatrix.GetRow(1).x, alembicMatrix.GetRow(1).y, alembicMatrix.GetRow(1).z, 0, alembicMatrix.GetRow(2).x, alembicMatrix.GetRow(2).y, alembicMatrix.GetRow(2).z, 0, alembicMatrix.GetRow(3).x, alembicMatrix.GetRow(3).y, alembicMatrix.GetRow(3).z, 1); Abc::M44d nodeWorldTransInv = nodeWorldTrans.inverse(); //ESS_LOG_WARNING("tick: "<<ticks<<" numParticles: "<<numParticles<<"\n"); ExoNullView nullView; particleGroupInterface groupInterface(particlesExt, obj, mMaxNode, &nullView); { ESS_PROFILE_SCOPE("AlembicPoints::SAVE - numParticlesLoop"); for (int i = 0; i < numParticles; ++i) { Abc::V3f pos(0.0); Abc::V3f vel(0.0); Abc::V3f scale(1.0); Abc::C4f color(0.5, 0.5, 0.5, 1.0); float age = 0; Abc::uint64_t id = 0; Abc::Quatd orientation(0.0, 0.0, 1.0, 0.0); Abc::Quatd spin(0.0, 0.0, 1.0, 0.0); // Particle size is a uniform scale multiplier in XSI. In Max, I need to learn where to get this // For now, we'll just default to 1 float width = 1.0f; ShapeType shapetype = ShapeType_Point; float shapeInstanceTime = (float)time; Abc::uint16_t shapeInstanceId = 0; #ifdef THINKING_PARTICLES if(pThinkingParticleMat){ if(pTPMasterSystemInt->IsAlive(i) == FALSE){ continue; } //TimeValue ageValue = particlesExt->GetParticleAgeByIndex(i); TimeValue ageValue = pTPMasterSystemInt->Age(i); if(ageValue == -1){ continue; } ESS_PROFILE_SCOPE("AlembicPoints::SAVE - numParticlesLoop - ThinkingParticles"); age = (float)GetSecondsFromTimeValue(ageValue); //pos = ConvertMaxPointToAlembicPoint(*particlesExt->GetParticlePositionByIndex(i)); pos = ConvertMaxPointToAlembicPoint(pTPMasterSystemInt->Position(i)); //vel = ConvertMaxVectorToAlembicVector(*particlesExt->GetParticleSpeedByIndex(i) * TIME_TICKSPERSEC); vel = ConvertMaxVectorToAlembicVector(pTPMasterSystemInt->Velocity(i) * TIME_TICKSPERSEC); scale = ConvertMaxScaleToAlembicScale(pTPMasterSystemInt->Scale(i)); scale *= pTPMasterSystemInt->Size(i); //ConvertMaxEulerXYZToAlembicQuat(*particlesExt->GetParticleOrientationByIndex(i), orientation); Matrix3 alignmentMatMax = pTPMasterSystemInt->Alignment(i); Abc::M44d alignmentMat; ConvertMaxMatrixToAlembicMatrix(alignmentMatMax, alignmentMat); /*alignmentMat = Abc::M44d( alignmentMatMax.GetRow(0).x, alignmentMatMax.GetRow(0).y, alignmentMatMax.GetRow(0).z, 0, alignmentMatMax.GetRow(1).x, alignmentMatMax.GetRow(1).y, alignmentMatMax.GetRow(1).z, 0, alignmentMatMax.GetRow(2).x, alignmentMatMax.GetRow(2).y, alignmentMatMax.GetRow(2).z, 0, alignmentMatMax.GetRow(3).x, alignmentMatMax.GetRow(3).y, alignmentMatMax.GetRow(3).z, 1);*/ //orientation = ConvertMaxQuatToAlembicQuat(extracctuat(alignmentMat), true); alignmentMat = alignmentMat * nodeWorldTransInv; orientation = extractQuat(alignmentMat); //ConvertMaxAngAxisToAlembicQuat(*particlesExt->GetParticleSpinByIndex(i), spin); ConvertMaxAngAxisToAlembicQuat(pTPMasterSystemInt->Spin(i), spin); id = particlesExt->GetParticleBornIndex(i); //seems to always return 0 //int nPid = pThinkingParticleMat->ParticleID(i); int nMatId = -1; Matrix3 meshTM; meshTM.IdentityMatrix(); BOOL bNeedDelete = FALSE; BOOL bChanged = FALSE; Mesh* pMesh = NULL; { ESS_PROFILE_SCOPE("AlembicPoints::SAVE - numParticlesLoop - ThinkingParticles - GetParticleRenderMesh"); pMesh = pThinkingParticleMat->GetParticleRenderMesh(ticks, mMaxNode, nullView, bNeedDelete, i, meshTM, bChanged); } if(pMesh){ ESS_PROFILE_SCOPE("AlembicPoints::SAVE - numParticlesLoop - ThinkingParticles - CacheShapeMesh"); meshInfo mi = CacheShapeMesh(pMesh, bNeedDelete, meshTM, nMatId, i, ticks, shapetype, shapeInstanceId, shapeInstanceTime); Abc::V3d min = pos + mi.bbox.min; Abc::V3d max = pos + mi.bbox.max; bbox.extendBy(min); bbox.extendBy(max); } else{ shapetype = ShapeType_Point; } } else #endif if(particlesExt && ipfSystem){ TimeValue ageValue = particlesExt->GetParticleAgeByIndex(i); if(ageValue == -1){ continue; } age = (float)GetSecondsFromTimeValue(ageValue); pos = ConvertMaxPointToAlembicPoint(*particlesExt->GetParticlePositionByIndex(i)); vel = ConvertMaxVectorToAlembicVector(*particlesExt->GetParticleSpeedByIndex(i) * TIME_TICKSPERSEC); scale = ConvertMaxScaleToAlembicScale(*particlesExt->GetParticleScaleXYZByIndex(i)); ConvertMaxEulerXYZToAlembicQuat(*particlesExt->GetParticleOrientationByIndex(i), orientation); ConvertMaxAngAxisToAlembicQuat(*particlesExt->GetParticleSpinByIndex(i), spin); //age = (float)GetSecondsFromTimeValue(particlesExt->GetParticleAgeByIndex(i)); id = particlesExt->GetParticleBornIndex(i); if(bAutomaticInstancing){ int nMatId = -1; if(ipfSystem){ if( groupInterface.setCurrentParticle(ticks, i) ){ nMatId = groupInterface.getCurrentMtlId(); } else{ ESS_LOG_WARNING("Error: cound retrieve material ID for particle mesh "<<i); } } Matrix3 meshTM; meshTM.IdentityMatrix(); BOOL bNeedDelete = FALSE; BOOL bChanged = FALSE; Mesh* pMesh = pMesh = particlesExt->GetParticleShapeByIndex(i); if(pMesh){ meshInfo mi = CacheShapeMesh(pMesh, bNeedDelete, meshTM, nMatId, i, ticks, shapetype, shapeInstanceId, shapeInstanceTime); Abc::V3d min = pos + mi.bbox.min; Abc::V3d max = pos + mi.bbox.max; bbox.extendBy(min); bbox.extendBy(max); } else{ shapetype = ShapeType_Point; } } else{ GetShapeType(particlesExt, i, ticks, shapetype, shapeInstanceId, shapeInstanceTime); } color = GetColor(particlesExt, i, ticks); } else if(pSimpleParticle){ if( ! pSimpleParticle->parts.Alive( i ) ) { continue; } pos = ConvertMaxPointToAlembicPoint(pSimpleParticle->ParticlePosition(ticks, i)); vel = ConvertMaxVectorToAlembicVector(pSimpleParticle->ParticleVelocity(ticks, i)); //simple particles have no scale? //simple particles have no orientation? age = (float)GetSecondsFromTimeValue( pSimpleParticle->ParticleAge(ticks, i) ); //simple particles have born index width = pSimpleParticle->ParticleSize(ticks, i); Abc::V3d min(pos.x - width/2, pos.y - width/2, pos.z - width/2); Abc::V3d max(pos.x + width/2, pos.y + width/2, pos.z + width/2); bbox.extendBy(min); bbox.extendBy(max); } { ESS_PROFILE_SCOPE("AlembicPoints::SAVE - numParticlesLoop - end loop save"); //move everything from world space to local space pos = pos * nodeWorldTransInv; Abc::V4f vel4(vel.x, vel.y, vel.z, 0.0); vel4 = vel4 * nodeWorldTransInv; vel.setValue(vel4.x, vel4.y, vel4.z); //scale = scale * nodeWorldTransInv; //orientation = Abc::extractQuat(orientation.toMatrix44() * nodeWorldTransInv); //spin = Abc::extractQuat(spin.toMatrix44() * nodeWorldTransInv); bbox.extendBy( pos ); positionVec.push_back( pos ); velocityVec.push_back( vel ); scaleVec.push_back( scale ); widthVec.push_back( width ); ageVec.push_back( age ); idVec.push_back( id ); orientationVec.push_back( orientation ); angularVelocityVec.push_back( spin ); shapeTypeVec.push_back( shapetype ); shapeInstanceIDVec.push_back( shapeInstanceId ); shapeTimeVec.push_back( shapeInstanceTime ); colorVec.push_back( color ); constantPos &= (pos == positionVec[0]); constantVel &= (vel == velocityVec[0]); constantScale &= (scale == scaleVec[0]); constantWidth &= (width == widthVec[0]); constantAge &= (age == ageVec[0]); constantOrientation &= (orientation == orientationVec[0]); constantAngularVel &= (spin == angularVelocityVec[0]); constantColor &= (color == colorVec[0]); // Set the archive bounding box // Positions for particles are already cnsider to be in world space if (mJob) { mJob->GetArchiveBBox().extendBy(pos); } } } } // if (numParticles > 1) // { // ESS_PROFILE_SCOPE("AlembicPoints::Save - vectorResize"); // if (constantPos) { positionVec.resize(1); } // if (constantVel) { velocityVec.resize(1); } // if (constantScale) { scaleVec.resize(1); } // if (constantWidth) { widthVec.resize(1); } // if (constantAge) { ageVec.resize(1); } // if (constantOrientation){ orientationVec.resize(1); } // if (constantAngularVel) { angularVelocityVec.resize(1); } //if (constantColor) { colorVec.resize(1); } // } { ESS_PROFILE_SCOPE("AlembicPoints::Save - sample writing"); // Store the information into our properties and points schema Abc::P3fArraySample positionSample( positionVec); Abc::P3fArraySample velocitySample(velocityVec); Abc::P3fArraySample scaleSample(scaleVec); Abc::FloatArraySample widthSample(widthVec); Abc::FloatArraySample ageSample(ageVec); Abc::FloatArraySample massSample(massVec); Abc::FloatArraySample shapeTimeSample(shapeTimeVec); Abc::UInt64ArraySample idSample(idVec); Abc::UInt16ArraySample shapeTypeSample(shapeTypeVec); Abc::UInt16ArraySample shapeInstanceIDSample(shapeInstanceIDVec); Abc::QuatfArraySample orientationSample(orientationVec); Abc::QuatfArraySample angularVelocitySample(angularVelocityVec); Abc::C4fArraySample colorSample(colorVec); mScaleProperty.set(scaleSample); mAgeProperty.set(ageSample); mMassProperty.set(massSample); mShapeTimeProperty.set(shapeTimeSample); mShapeTypeProperty.set(shapeTypeSample); mShapeInstanceIDProperty.set(shapeInstanceIDSample); mOrientationProperty.set(orientationSample); mAngularVelocityProperty.set(angularVelocitySample); mColorProperty.set(colorSample); mPointsSample.setPositions(positionSample); mPointsSample.setVelocities(velocitySample); mPointsSample.setWidths(AbcG::OFloatGeomParam::Sample(widthSample, AbcG::kVertexScope)); mPointsSample.setIds(idSample); mPointsSample.setSelfBounds(bbox); mPointsSchema.getChildBoundsProperty().set( bbox); mPointsSchema.set(mPointsSample); } mNumSamples++; //mInstanceNames.pop_back(); if(bAutomaticInstancing){ saveCurrentFrameMeshes(); } if(bRenderStateForced){ ipfSystem->SetRenderState(false); } if(bLastFrame){ ESS_PROFILE_SCOPE("AlembicParticles::Save - save instance names property"); std::vector<std::string> instanceNames(mNumShapeMeshes); for(faceVertexHashToShapeMap::iterator it = mShapeMeshCache.begin(); it != mShapeMeshCache.end(); it++){ std::stringstream pathStream; pathStream << "/" << it->second.name<< "/" << it->second.name <<"Shape"; instanceNames[it->second.nMeshInstanceId] = pathStream.str(); } //for some reason the .dims property is not written when there is exactly one entry if we don't push an empty string //having an extra unreferenced entry seems to be harmless instanceNames.push_back(""); mInstanceNamesProperty.set(Abc::StringArraySample(instanceNames)); } return true; }
bool AlembicWriteJob::PreProcess() { // check filenames if(mFileName.empty()) { ESS_LOG_WARNING("[alembic] No filename specified."); return false; } //// check objects //if(mSelection.Count() == 0) //{ // ESS_LOG_WARNING("[alembic] No objects specified."); // return false; //} // check frames if(mFrames.size() == 0) { ESS_LOG_WARNING("[alembic] No frames specified."); return false; } const bool bParticleMesh = GetOption("exportParticlesAsMesh"); bool bMergePolyMeshSubtree = GetOption("mergePolyMeshSubtree"); bool bSelectParents = GetOption("includeParentNodes");/*|| !bFlattenHierarchy || bTransformCache*/ const bool bSelectChildren = false; bool bTransformCache = GetOption("transformCache"); const bool bFlattenHierarchy = GetOption("flattenHierarchy"); if(bMergePolyMeshSubtree){ bTransformCache = false; //bSelectParents = true; } bcsgSelection::types buildSelection = bcsgSelection::ALL; const bool bExportSelected = GetOption("exportSelected"); const bool bObjectsParameterExists = GetOption("objectsParameterExists"); if(bExportSelected){ //copy max selection buildSelection = bcsgSelection::APP; } else if(bObjectsParameterExists){ //select nothing when building, fill in later from parameter data buildSelection = bcsgSelection::NONE; } else{ //select everything } int nNumNodes = 0; exoSceneRoot = buildCommonSceneGraph(nNumNodes, true, buildSelection); //WARNING ILM robot right crashes when printing //printSceneGraph(exoSceneRoot, false); if(bObjectsParameterExists){ //Might be better to use refineSelection here, but call a function that sets up dccSelected flag first, then delete this function from codebase selectNodes(exoSceneRoot, mObjectsMap, bSelectParents, bSelectChildren, !bTransformCache); bool bAllResolved = true; if(bObjectsParameterExists){ for(SceneNode::SelectionT::iterator it = mObjectsMap.begin(); it != mObjectsMap.end(); it++){ if(it->second == false){ bAllResolved = false; ESS_LOG_ERROR("Could not resolve objects identifier: "<<it->first); } } } if(bAllResolved){ removeUnselectedNodes(exoSceneRoot); } else{ return false; } } else if(bExportSelected){ refineSelection(exoSceneRoot, bSelectParents, bSelectChildren, !bTransformCache); removeUnselectedNodes(exoSceneRoot); } if(bMergePolyMeshSubtree){ replacePolyMeshSubtree<SceneNodeMaxPtr, SceneNodeMax>(exoSceneRoot); } if(bFlattenHierarchy){ nNumNodes = 0; flattenSceneGraph(exoSceneRoot, nNumNodes); } if(GetOption("renameConflictingNodes")){ renameConflictingNodes(exoSceneRoot, false); } else{ int nRenameCount = renameConflictingNodes(exoSceneRoot, true); if(nRenameCount){ ESS_LOG_ERROR("Can not export due sibling node naming conflict. Consider exporting with renameConflictingNodes=true"); return false; } } const bool bUseOgawa = (bool)GetOption("useOgawa"); // init archive (use a locally scoped archive) std::string sceneFileName = ""; sceneFileName.append( EC_MSTR_to_UTF8( mApplication->GetCurFilePath() ) ); try { if(bUseOgawa){ mArchive = CreateArchiveWithInfo( Alembic::AbcCoreOgawa::WriteArchive(), mFileName.c_str(), getExporterName( "3DS Max " EC_QUOTE( crate_Max_Version ) ).c_str(), getExporterFileName( sceneFileName ).c_str(), Abc::ErrorHandler::kThrowPolicy); } else{ mArchive = CreateArchiveWithInfo( Alembic::AbcCoreHDF5::WriteArchive( true ), mFileName.c_str(), getExporterName( "3DS Max " EC_QUOTE( crate_Max_Version ) ).c_str(), getExporterFileName( sceneFileName ).c_str(), Abc::ErrorHandler::kThrowPolicy); } } catch(Alembic::Util::Exception& e) { std::string exc(e.what()); ESS_LOG_ERROR("[alembic] Error writing to file: "<<e.what()); return false; } // get the frame rate mFrameRate = static_cast<float>(GetFrameRate()); if(mFrameRate == 0.0f) { mFrameRate = 25.0f; } std::vector<AbcA::chrono_t> frames; for(LONG i=0;i<mFrames.size();i++) { frames.push_back(mFrames[i] / mFrameRate); } // create the sampling double timePerSample = 1.0 / mFrameRate; if(frames.size() > 1) { if( ! HasAlembicWriterLicense() ) { if( HasAlembicInvalidLicense() ) { ESS_LOG_ERROR("[alembic] No license available and EXOCORTEX_ALEMBIC_NO_DEMO defined, aborting." ); return false; } if(frames.size() > 75) { frames.resize(75); ESS_LOG_WARNING("[ExocortexAlembic] Writer license not found: Maximum exportable samplecount is 75!"); } } double timePerCycle = frames[frames.size()-1] - frames[0]; AbcA::TimeSamplingType samplingType((boost::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); } m_ArchiveBoxProp = AbcG::CreateOArchiveBounds(mArchive,mTs); std::list<PreProcessStackElement> sceneStack; sceneStack.push_back(PreProcessStackElement(exoSceneRoot, mArchive.getTop())); try{ while( !sceneStack.empty() ) { PreProcessStackElement sElement = sceneStack.back(); SceneNodePtr eNode = sElement.eNode; sceneStack.pop_back(); Abc::OObject oParent = sElement.oParent; Abc::OObject oNewParent; AlembicObjectPtr pNewObject; if(eNode->type == SceneNode::SCENE_ROOT){ //we do not want to export the Scene_Root (the alembic archive has one already) } else if(eNode->type == SceneNode::ITRANSFORM || eNode->type == SceneNode::ETRANSFORM){ pNewObject.reset(new AlembicXForm(eNode, this, oParent)); } else if(eNode->type == SceneNode::CAMERA){ pNewObject.reset(new AlembicCamera(eNode, this, oParent)); } else if(eNode->type == SceneNode::POLYMESH || eNode->type == SceneNode::POLYMESH_SUBTREE){ pNewObject.reset(new AlembicPolyMesh(eNode, this, oParent)); } //TODO: as far I recall we dont support SUBD. verify... //else if(eNode->type == SceneNode::SUBD){ // pNewObject.reset(new AlembicSubD(eNode, this, oParent)); //} else if(eNode->type == SceneNode::CURVES){ pNewObject.reset(new AlembicCurves(eNode, this, oParent)); } else if(eNode->type == SceneNode::PARTICLES || eNode->type == SceneNode::PARTICLES_TP){ if(bParticleMesh){ pNewObject.reset(new AlembicPolyMesh(eNode, this, oParent)); } else{ pNewObject.reset(new AlembicPoints(eNode, this, oParent)); } } //else{ // ESS_LOG_WARNING("Unknown type: not exporting "<<eNode->name);//Export as transform, and give warning? //} if(pNewObject){ //add the AlembicObject to export list if it is not being skipped AddObject(pNewObject); } if(pNewObject){ oNewParent = oParent.getChild(eNode->name); } else{ //this case should be unecessary //if we skip node A, we parent node A's children to the parent of A oNewParent = oParent; } if(oNewParent.valid()){ for( std::list<SceneNodePtr>::iterator it = eNode->children.begin(); it != eNode->children.end(); it++){ sceneStack.push_back(PreProcessStackElement(*it, oNewParent)); } } else{ ESS_LOG_ERROR("Do not have refernce to parent."); return false; } } }catch( std::exception& exp ){ ESS_LOG_ERROR("An std::exception occured: "<<exp.what()); return false; }catch(...){ ESS_LOG_ERROR("Exception ecountered when exporting."); } if(mObjects.empty()){ ESS_LOG_ERROR("No objects specified."); return false; } return true; }