int removeUnselectedNodes(SceneNodePtr root) { ESS_PROFILE_FUNC(); int nNumNodes = 0; SceneNodePtr newRoot = root; std::list<FlattenStackElement> sceneStack; // push a reference to each child to the stack for (SceneChildIterator it = root->children.begin(); it != root->children.end(); it++) { SceneNodePtr fileNode = *it; sceneStack.push_back(FlattenStackElement(fileNode, root)); } // clear the children since we may be changing what is parented to it root->children.clear(); while (!sceneStack.empty()) { FlattenStackElement sElement = sceneStack.back(); SceneNodePtr fileNode = sElement.currNode; SceneNodePtr parentNode = sElement.currParentNode; // a node from the original tree, its // childrens will have been cleared // we will add child nodes to it that meet the correct criteria sceneStack.pop_back(); if (fileNode->selected) { parentNode->children.push_back(fileNode); fileNode->parent = parentNode.get(); fileNode->selected = false; nNumNodes++; for (SceneChildIterator it = fileNode->children.begin(); it != fileNode->children.end(); it++) { sceneStack.push_back(FlattenStackElement(*it, fileNode)); } } else { // if a shape node is not selected its parent transform should become an // ITRANSFORM if (isShapeNode(fileNode->type) && fileNode->parent && fileNode->parent->selected && fileNode->parent->type == SceneNode::ETRANSFORM) { fileNode->parent->type = SceneNode::ITRANSFORM; } for (SceneChildIterator it = fileNode->children.begin(); it != fileNode->children.end(); it++) { sceneStack.push_back(FlattenStackElement(*it, parentNode)); } } fileNode->children.clear(); } return nNumNodes; }
int selectTransformNodes(SceneNodePtr root) { ESS_PROFILE_FUNC(); std::list<SelectChildrenStackElement> sceneStack; sceneStack.push_back(SelectChildrenStackElement(root, false)); int nSelectionCount = 0; while( !sceneStack.empty() ) { SelectChildrenStackElement sElement = sceneStack.back(); SceneNodePtr eNode = sElement.eNode; sceneStack.pop_back(); if(eNode->type == SceneNode::NAMESPACE_TRANSFORM || eNode->type == SceneNode::ETRANSFORM || eNode->type == SceneNode::ITRANSFORM){ eNode->selected = true; nSelectionCount++; } for( std::list<SceneNodePtr>::iterator it = eNode->children.begin(); it != eNode->children.end(); it++){ sceneStack.push_back(SelectChildrenStackElement(*it, false)); } } root->selected = true; return nSelectionCount; }
void AlembicVisibilityController::GetValueLocalTime(TimeValue t, void *ptr, Interval &valid, GetSetMethod method) { ESS_CPP_EXCEPTION_REPORTING_START ESS_PROFILE_FUNC(); Interval interval = FOREVER; MCHAR const *strPath = NULL; this->pblock->GetValue(AlembicVisibilityController::ID_PATH, t, strPath, interval); MCHAR const *strIdentifier = NULL; this->pblock->GetValue(AlembicVisibilityController::ID_IDENTIFIER, t, strIdentifier, interval); float fTime; this->pblock->GetValue(AlembicVisibilityController::ID_TIME, t, fTime, interval); BOOL bMuted; this->pblock->GetValue(AlembicVisibilityController::ID_MUTED, t, bMuted, interval); if (bMuted || !strPath || !strIdentifier) { return; } std::string szPath = EC_MCHAR_to_UTF8(strPath); std::string szIdentifier = EC_MCHAR_to_UTF8(strIdentifier); AbcG::IObject iObj = getObjectFromArchive(szPath, szIdentifier); if (!iObj.valid()) { return; } alembic_fillvis_options visOptions; visOptions.pIObj = &iObj; visOptions.dTicks = t; visOptions.bOldVisibility = m_bOldVisibility; AlembicImport_FillInVis(visOptions); float fBool = visOptions.bVisibility ? 1.0f : 0.0f; m_bOldVisibility = visOptions.bVisibility; valid = interval; if (method == CTRL_ABSOLUTE) { float *fInVal = (float *)ptr; *fInVal = fBool; } else { // CTRL_RELATIVE float *fInVal = (float *)ptr; *fInVal = fBool * (*fInVal); } ESS_CPP_EXCEPTION_REPORTING_END }
Abc::FloatArraySamplePtr getKnotVector(AbcG::ICurves& obj) { ESS_PROFILE_FUNC(); Abc::ICompoundProperty arbGeom = obj.getSchema().getArbGeomParams(); if (!arbGeom.valid()) { return Abc::FloatArraySamplePtr(); } if (arbGeom.getPropertyHeader(".knot_vectors") != NULL) { Abc::IFloatArrayProperty knotProp = Abc::IFloatArrayProperty(arbGeom, ".knot_vectors"); if (knotProp.valid() && knotProp.getNumSamples() != 0) { return knotProp.getValue(0); } } if (arbGeom.getPropertyHeader(".knot_vector") != NULL) { Abc::IFloatArrayProperty knotProp = Abc::IFloatArrayProperty(arbGeom, ".knot_vector"); if (knotProp.valid() && knotProp.getNumSamples() != 0) { return knotProp.getValue(0); } } return Abc::FloatArraySamplePtr(); }
void addControllersToModifierV2(const std::string& modkey, const std::string& modname, std::vector<AbcProp>& props, const std::string& file, const std::string& identifier, const std::string& category, alembic_importoptions &options, INode* pNode) { ESS_PROFILE_FUNC(); std::stringstream evalStream; std::string nodeName("$"); if(pNode){ evalStream<<GET_MAXSCRIPT_NODE(pNode); nodeName = std::string("mynode2113"); } for(int i=0; i<props.size(); i++){ std::string propName = props[i].name; std::string& val = props[i].displayVal; bool& bConstant = props[i].bConstant; const AbcA::DataType& datatype = props[i].propHeader.getDataType(); const AbcA::MetaData& metadata = props[i].propHeader.getMetaData(); if(datatype.getPod() == AbcA::kFloat32POD){ std::stringstream propStream; propStream<<propName; if(datatype.getExtent() == 1){ addFloatControllerV2(evalStream, options, nodeName, modkey, propName, file, identifier, category, propStream.str()); } else if(datatype.getExtent() == 3){ 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"; addFloatControllerV2(evalStream, options, nodeName, modkey, propName + std::string("x"), file, identifier, category, xStream.str()); addFloatControllerV2(evalStream, options, nodeName, modkey, propName + std::string("y"), file, identifier, category, yStream.str()); addFloatControllerV2(evalStream, options, nodeName, modkey, propName + std::string("z"), file, identifier, category, zStream.str()); } } else if(datatype.getPod() == AbcA::kInt32POD){ std::stringstream propStream; propStream<<propName; if(datatype.getExtent() == 1){ addFloatControllerV2(evalStream, options, nodeName, modkey, propName, file, identifier, category, propStream.str()); } } else{ } evalStream<<"\n"; } //ESS_LOG_WARNING(evalStream.str()); ExecuteMAXScriptScript( EC_UTF8_to_TCHAR((char*)evalStream.str().c_str())); }
bool validateCurveData(Abc::P3fArraySamplePtr pCurvePos, Abc::Int32ArraySamplePtr pCurveNbVertices, Abc::UInt16ArraySamplePtr pOrders, Abc::FloatArraySamplePtr pKnotVec, AbcG::CurveType type) { ESS_PROFILE_FUNC(); int nDefaultOrder = 4; const int numCurves = (int)pCurveNbVertices->size(); const int numControl = (int)pCurvePos->size(); int numControlNB = 0; for (int i = 0; i < pCurveNbVertices->size(); i++) { numControlNB += pCurveNbVertices->get()[i]; } if (numControl != numControlNB) { ESS_LOG_ERROR( "Size mismatch between vertices and nbVertices. Cannot load curve."); return false; } if (pOrders && pCurveNbVertices->size() != pOrders->size()) { ESS_LOG_ERROR( "Size mismatch between numOrders and nbVertices. Cannot load curve."); return false; } if (pKnotVec) { int abcTotalKnots = 0; // numControl + numCurves * (nDefaultOrder - 2) ; if (pOrders) { // calculate the expected knot vec size for (int i = 0; i < pCurveNbVertices->size(); i++) { abcTotalKnots += pCurveNbVertices->get()[i] + pOrders->get()[i] - 2; } } else { // single order int nOrder = 0; if (type == AbcG::kCubic) { nOrder = 4; } else if (type == AbcG::kLinear) { nOrder = 2; } abcTotalKnots = numControl + numCurves * (nOrder - 2); } if (abcTotalKnots != pKnotVec->size()) { ESS_LOG_ERROR("Knot vector has the wrong size. Cannot load curve."); } } return true; }
void addControllersToModifier(const std::string& modkey, const std::string& modname, std::vector<AbcProp>& props, const std::string& target, const std::string& type, const std::string& file, const std::string& identifier, alembic_importoptions &options) { ESS_PROFILE_FUNC(); //the script assumes a single object is selected std::stringstream evalStream; for(int i=0; i<props.size(); i++){ std::string propName = props[i].name; std::string& val = props[i].displayVal; bool& bConstant = props[i].bConstant; const AbcA::DataType& datatype = props[i].propHeader.getDataType(); const AbcA::MetaData& metadata = props[i].propHeader.getMetaData(); if(datatype.getPod() == AbcA::kFloat32POD){ std::stringstream propStream; propStream<<target<<"."<<type<<"."<<propName; if(datatype.getExtent() == 1){ addFloatController(evalStream, options, modkey, propName, file, identifier, propStream.str()); } else if(datatype.getExtent() == 3){ 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"; addFloatController(evalStream, options, modkey, propName + std::string("x"), file, identifier, xStream.str()); addFloatController(evalStream, options, modkey, propName + std::string("y"), file, identifier, yStream.str()); addFloatController(evalStream, options, modkey, propName + std::string("z"), file, identifier, zStream.str()); } } else{ } evalStream<<"\n"; } //ESS_LOG_WARNING(evalStream.str()); ExecuteMAXScriptScript( EC_UTF8_to_TCHAR((char*)evalStream.str().c_str())); }
Abc::UInt16ArraySamplePtr getCurveOrders(AbcG::ICurves& obj) { ESS_PROFILE_FUNC(); Abc::ICompoundProperty arbGeom = obj.getSchema().getArbGeomParams(); if(!arbGeom.valid()){ return Abc::UInt16ArraySamplePtr(); } if ( arbGeom.getPropertyHeader( ".orders" ) != NULL ){ Abc::IUInt16ArrayProperty orders = Abc::IUInt16ArrayProperty( arbGeom, ".orders" ); if(orders.valid() && orders.getNumSamples() != 0){ return orders.getValue(0); } } return Abc::UInt16ArraySamplePtr(); }
void importMetadata(INode* pNode, AbcG::IObject& iObj) { ESS_PROFILE_FUNC(); AbcG::IObject* metadataChild = NULL; if (getCompoundFromObject(iObj).getPropertyHeader(".metadata") == NULL) { return; } Abc::IStringArrayProperty metaDataProp = Abc::IStringArrayProperty(getCompoundFromObject(iObj), ".metadata"); Abc::StringArraySamplePtr ptr = metaDataProp.getValue(0); // for(unsigned int i=0;i<ptr->size();i++){ // const char* name = ptr->get()[i].c_str(); // Abc::StringArraySamplePtr ptr = metaDataProp.getValue(0); // //} std::stringstream exeBuffer; exeBuffer << GET_MAXSCRIPT_NODE(pNode); exeBuffer << "ImportMetadata mynode2113"; exeBuffer << "#("; for (int i = 0; i < ptr->size() - 1; i++) { exeBuffer << "\""; exeBuffer << ptr->get()[i]; exeBuffer << "\", "; } exeBuffer << "\""; exeBuffer << ptr->get()[ptr->size() - 1]; exeBuffer << "\")"; exeBuffer << " \n"; ExecuteMAXScriptScript(EC_UTF8_to_TCHAR((char*)exeBuffer.str().c_str())); // delete[] szBuffer; }
int renameConflictingNodes(SceneNodePtr root, bool bValidate) { ESS_PROFILE_FUNC(); clearIdentifierMap(); std::list<SelectChildrenStackElement> sceneStack; sceneStack.push_back(SelectChildrenStackElement(root, false)); int nRenameCount = 0; while (!sceneStack.empty()) { SelectChildrenStackElement sElement = sceneStack.back(); SceneNodePtr eNode = sElement.eNode; sceneStack.pop_back(); if (eNode->type == SceneNode::ETRANSFORM || eNode->type == SceneNode::ITRANSFORM) { std::string parent; if (eNode->parent) { parent = eNode->parent->dccIdentifier; } bool bRenamed = false; eNode->name = getUniqueName(parent, eNode->name, bValidate, bRenamed); if (bRenamed) { nRenameCount++; } } for (std::list<SceneNodePtr>::iterator it = eNode->children.begin(); it != eNode->children.end(); it++) { sceneStack.push_back(SelectChildrenStackElement(*it, false)); } } clearIdentifierMap(); return nRenameCount; }
int selectPolyMeshShapeNodes(SceneNodePtr root) { ESS_PROFILE_FUNC(); std::list<SelectChildrenStackElement> sceneStack; sceneStack.push_back(SelectChildrenStackElement(root, false)); int nSelectionCount = 0; while( !sceneStack.empty() ) { SelectChildrenStackElement sElement = sceneStack.back(); SceneNodePtr eNode = sElement.eNode; sceneStack.pop_back(); if(eNode->type == SceneNode::POLYMESH){ eNode->selected = true; nSelectionCount++; SceneNode* currNode = eNode->parent; while(currNode){ if(!currNode->selected) nSelectionCount++; currNode->selected = true; currNode = currNode->parent; } } for( std::list<SceneNodePtr>::iterator it = eNode->children.begin(); it != eNode->children.end(); it++){ sceneStack.push_back(SelectChildrenStackElement(*it, false)); } } root->selected = true; return nSelectionCount; }
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 flattenSceneGraph(SceneNodePtr root, int nNumNodes) { ESS_PROFILE_FUNC(); SceneNodePtr newRoot = root; std::list<FlattenStackElement> sceneStack; //push a reference to each child to the stack for(SceneChildIterator it = root->children.begin(); it != root->children.end(); it++){ SceneNodePtr fileNode = *it; sceneStack.push_back(FlattenStackElement(fileNode, root)); } //clear the children since we may be changing what is parented to it root->children.clear(); while( !sceneStack.empty() ) { FlattenStackElement sElement = sceneStack.back(); SceneNodePtr fileNode = sElement.currNode; SceneNodePtr parentNode = sElement.currParentNode;//a node from the original tree, its childrens will have been cleared //we will add child nodes to it that meet the correct criteria sceneStack.pop_back(); //a nodes that we want keep, so connect it to the parent if (fileNode->type == SceneNode::NAMESPACE_TRANSFORM || //namespace transform (XSI model) fileNode->type == SceneNode::ETRANSFORM || //shape node parent transform isShapeNode(fileNode->type) //shape node ) { //mergedpolymesh node would apply here parentNode->children.push_back(fileNode); fileNode->parent = parentNode.get(); nNumNodes++; } //here we set what the parent is going to be for the file node we pushing to the stack // - if parentNode is passed instead of fileNode, the subtree starting at fileNode is being skipped if(fileNode->type == SceneNode::NAMESPACE_TRANSFORM){ for(SceneChildIterator it = fileNode->children.begin(); it != fileNode->children.end(); it++){ sceneStack.push_back( FlattenStackElement( *it, fileNode ) ); } } else if(fileNode->type == SceneNode::ETRANSFORM){ for(SceneChildIterator it = fileNode->children.begin(); it != fileNode->children.end(); it++){ if(isShapeNode((*it)->type)){ sceneStack.push_back( FlattenStackElement( *it, fileNode ) ); } else{ sceneStack.push_back( FlattenStackElement( *it, parentNode ) ); } } } else{ for(SceneChildIterator it = fileNode->children.begin(); it != fileNode->children.end(); it++){ sceneStack.push_back( FlattenStackElement( *it, parentNode ) ); } } fileNode->children.clear(); } }
Modifier* createDisplayModifier(std::string modkey, std::string modname, std::vector<AbcProp>& props, INode* pNode) { ESS_PROFILE_FUNC(); //the script assumes a single object is selected std::stringstream evalStream; std::string nodeName("$"); if(pNode){ evalStream<<GET_MAXSCRIPT_NODE(pNode); nodeName = std::string("mynode2113"); } evalStream<<"propModifier = EmptyModifier()"<<"\n"; evalStream<<"propModifier.name = \""<<modkey<<"\""<<"\n"; evalStream<<"modCount = "<<nodeName<<".modifiers.count"<<"\n"; evalStream<<"addmodifier "<<nodeName<<" propModifier before:modCount"<<"\n"; evalStream<<nodeName<<".modifiers[\""<<modkey<<"\"].enabled = false"<<"\n"; evalStream<<"propAttribute = attributes propAttribute"<<"\n"; evalStream<<"("<<"\n"; evalStream<<"parameters propAttributePRM1 rollout:propAttributeRLT1"<<"\n"; evalStream<<"("<<"\n"; for(int i=0; i<props.size(); i++){ std::string& name = props[i].name; std::string& val = props[i].displayVal; bool& bConstant = props[i].bConstant; const AbcA::DataType& datatype = props[i].propHeader.getDataType(); const AbcA::MetaData& metadata = props[i].propHeader.getMetaData(); if(datatype.getPod() == AbcA::kInt32POD && datatype.getExtent() == 1){ evalStream<<name<<" type:#integer animatable:true ui:e"<<name<<" default:"<<val; } else if(datatype.getPod() == AbcA::kFloat32POD && datatype.getExtent() == 1){ evalStream<<name<<" type:#float animatable:true ui:e"<<name<<" default:"<<val; } else if(datatype.getPod() == AbcA::kFloat32POD && datatype.getExtent() == 3){ //if(metadata.get("interpretation") == std::string("rgb")){ // evalStream<<name<<" type:#color animatable:false ui:e"<<name<<" default:(["<<val<<"] as color)"; //} //else{ //evalStream<<name<<" type:#point3 animatable:false ui:e"<<name<<" ["<<val<<"]"; evalStream<<name<<"x type:#float animatable:true ui:e"<<name<<"x default:300\n"; evalStream<<name<<"y type:#float animatable:true ui:e"<<name<<"y default:300\n"; evalStream<<name<<"z type:#float animatable:true ui:e"<<name<<"z default:300\n"; //} } else{ evalStream<<name<<" type:#string animatable:false ui:e"<<name<<" default:\""<<val<<"\""; } evalStream<<"\n"; } evalStream<<")"<<"\n"; evalStream<<"rollout propAttributeRLT1 \""<<modname<<"\""<<"\n"; evalStream<<"("<<"\n"; for(int i=0; i<props.size(); i++){ std::string& name = props[i].name; bool& bConstant = props[i].bConstant; const AbcA::DataType& datatype = props[i].propHeader.getDataType(); const AbcA::MetaData& metadata = props[i].propHeader.getMetaData(); const int nSize = (const int) props[i].displayVal.size(); if(datatype.getPod() == AbcA::kInt32POD && datatype.getExtent() == 1){ evalStream<<"label lbl"<<name<<" \""<<name<<"\" align:#left fieldWidth:140\n"; evalStream<<"spinner e"<<name<<" \"\" type:#integer range:[-9999999,9999999,0] align:#left labelOnTop:true\n"; } else if(datatype.getPod() == AbcA::kFloat32POD && datatype.getExtent() == 1){ evalStream<<"label lbl"<<name<<" \""<<name<<"\" align:#left fieldWidth:140\n"; evalStream<<"spinner e"<<name<<" \"\" type:#float range:[-9999999,9999999,0]align:#left labelOnTop:true\n"; } else if(datatype.getPod() == AbcA::kFloat32POD && datatype.getExtent() == 3){ evalStream<<"label lbl"<<name<<" \""<<name<<"\" align:#left fieldWidth:140\n"; evalStream<<"spinner e"<<name<<"x\"\" across:3 type:#float range:[-9999999,9999999,0] fieldWidth:39 readOnly:true\n"; evalStream<<"spinner e"<<name<<"y\"\" type:#float range:[-9999999,9999999,0] fieldWidth:39\n"; evalStream<<"spinner e"<<name<<"z\"\" type:#float range:[-9999999,9999999,0] fieldWidth:39\n"; } else{ //TODO: better fit for large strings evalStream<<"edittext e"<<name<<" \" "<<name<<"\" fieldWidth:140 "; if(nSize > 140){ evalStream<<"height:54"; } evalStream<<" labelOnTop:true"; if(bConstant) evalStream<<" readOnly:true"; } evalStream<<"\n"; } //evalStream<<"on propAttributePRM1 changed do\n"; //evalStream<<"("<<"\n"; //for(int i=0; i<props.size(); i++){ // std::string& name = props[i].name; // const AbcA::DataType& datatype = props[i].propHeader.getDataType(); // const AbcA::MetaData& metadata = props[i].propHeader.getMetaData(); // evalStream<<"e"<<name<<".text = "<<name<<" as string"; // evalStream<<"\n"; //} //evalStream<<")"<<"\n"; evalStream<<")"<<"\n"; evalStream<<")"<<"\n"; evalStream<<"custattributes.add "<<nodeName<<".modifiers[\""<<modkey<<"\"] propAttribute baseobject:false"<<"\n"; //ESS_LOG_WARNING(evalStream.str()); evalStream<<nodeName<<".modifiers[\""<<modkey<<"\"]\n"; FPValue fpVal; ExecuteMAXScriptScript( EC_UTF8_to_TCHAR((char*)evalStream.str().c_str()), 0, &fpVal); Modifier* pMod = (Modifier*)fpVal.r; return pMod; }
int refineSelection(SceneNodePtr root, bool bSelectParents, bool bChildren, bool bSelectShapeNodes) { ESS_PROFILE_FUNC(); std::list<SelectChildrenStackElement> sceneStack; sceneStack.push_back(SelectChildrenStackElement(root, false)); int nSelectionCount = 0; while( !sceneStack.empty() ) { SelectChildrenStackElement sElement = sceneStack.back(); SceneNodePtr eNode = sElement.eNode; sceneStack.pop_back(); bool bSelected = false; //check if the node matches a full path if(eNode->type == SceneNode::ETRANSFORM || eNode->type == SceneNode::ITRANSFORM || eNode->type == SceneNode::NAMESPACE_TRANSFORM) { if(eNode->dccSelected){ //this node's name matches one of the names from the selection map, so select it if(!eNode->selected) nSelectionCount++; eNode->selected = true; if(eNode->type == SceneNode::ETRANSFORM && bSelectShapeNodes) { //Select the shape nodes first for(std::list<SceneNodePtr>::iterator it=eNode->children.begin(); it != eNode->children.end(); it++) { if(::isShapeNode((*it)->type)){ if(!(*it)->selected) nSelectionCount++; (*it)->selected = true; break; } } } //then select the parents if(bSelectParents){// select all parent nodes SceneNode* currNode = eNode->parent; while(currNode){ if(!currNode->selected) nSelectionCount++; currNode->selected = true; currNode = currNode->parent; } } if(bChildren){// select the children bSelected = true; } } } if(sElement.bSelectChildren){ bSelected = true; if(!eNode->selected) nSelectionCount++; eNode->selected = true; } for( std::list<SceneNodePtr>::iterator it = eNode->children.begin(); it != eNode->children.end(); it++){ sceneStack.push_back(SelectChildrenStackElement(*it, bSelected)); } } root->selected = true; return nSelectionCount; }
int selectNodes(SceneNodePtr root, SceneNode::SelectionT& selectionMap, bool bSelectParents, bool bChildren, bool bSelectShapeNodes, bool isMaya) { ESS_PROFILE_FUNC(); SceneNode::SelectionT::iterator selectionEnd = selectionMap.end(); std::list<SelectChildrenStackElement> sceneStack; sceneStack.push_back(SelectChildrenStackElement(root, false)); int nSelectionCount = 0; while( !sceneStack.empty() ) { SelectChildrenStackElement sElement = sceneStack.back(); SceneNodePtr eNode = sElement.eNode; sceneStack.pop_back(); bool bSelected = false; //check if the node matches a full path if(eNode->type == SceneNode::ETRANSFORM || eNode->type == SceneNode::ITRANSFORM || eNode->type == SceneNode::NAMESPACE_TRANSFORM || eNode->type == SceneNode::HAIR)// removed to be able to export hair properly in Maya! { SceneNode::SelectionT::iterator selectionIt = selectionMap.find(eNode->dccIdentifier); if(selectionIt != selectionEnd){ //to keep track which ones resolved selectionMap[eNode->dccIdentifier] = true; } //otherwise, check if the node names match if(selectionIt == selectionEnd){ std::string nodeName = removeXfoSuffix(eNode->name); selectionIt = selectionMap.find(nodeName); if(selectionIt != selectionEnd){ //to keep track which ones resolved selectionMap[nodeName] = true; } } if(selectionIt != selectionEnd){ //this node's name matches one of the names from the selection map, so select it if(!eNode->selected) nSelectionCount++; eNode->selected = true; if(eNode->type == SceneNode::ETRANSFORM && bSelectShapeNodes) { //Select the shape nodes first if (isMaya) { for(std::list<SceneNodePtr>::reverse_iterator it=eNode->children.rbegin(); it != eNode->children.rend(); ++it) { if(::isShapeNode((*it)->type))//MergedPolyMesh node should work here... { if(!(*it)->selected) nSelectionCount++; (*it)->selected = true; break; } } } else { for(std::list<SceneNodePtr>::iterator it=eNode->children.begin(); it != eNode->children.end(); it++) { if(::isShapeNode((*it)->type)){ if(!(*it)->selected) nSelectionCount++; (*it)->selected = true; break; } } } } //then select the parents if(bSelectParents){// select all parent nodes SceneNode* currNode = eNode->parent; while(currNode){ if(!currNode->selected) nSelectionCount++; currNode->selected = true; currNode = currNode->parent; } } if(bChildren){// select the children bSelected = true; } } // if(selectionIt != } // if(eNode->type == if(sElement.bSelectChildren){ bSelected = true; if(!eNode->selected) nSelectionCount++; eNode->selected = true; } for( std::list<SceneNodePtr>::iterator it = eNode->children.begin(); it != eNode->children.end(); it++){ sceneStack.push_back(SelectChildrenStackElement(*it, bSelected)); } } root->selected = true; return nSelectionCount; }
//we have to save out all mesh encountered on the current frame of this object immediately, because //the pointers will no longer be valid when the object is evaluated at a new time void AlembicPoints::saveCurrentFrameMeshes() { ESS_PROFILE_FUNC(); for(int i=0; i<mMeshesToSaveForCurrentFrame.size(); i++){ //TODO: save immediately instead accumulating in a vector meshInfo* mi = mMeshesToSaveForCurrentFrame[i]; if(mi->pMesh){ Mesh* pMesh = mi->pMesh; //mi->pMesh = NULL;//each mesh only needs to be saved once //Matrix3 worldTrans; //worldTrans.IdentityMatrix(); CommonOptions options; options.SetOption("exportNormals", mJob->GetOption("exportNormals")); options.SetOption("exportMaterialIds", mJob->GetOption("exportMaterialIds")); //gather the mesh data mi->meshTM.IdentityMatrix(); IntermediatePolyMesh3DSMax finalPolyMesh; { ESS_PROFILE_SCOPE("AlembicPoints::saveCurrentFrameMeshes - finalPolyMesh.Save"); Imath::M44f transform44f; ConvertMaxMatrixToAlembicMatrix( mi->meshTM, transform44f ); SceneNodeMaxParticlesPtr inputSceneNode(new SceneNodeMaxParticles(pMesh, NULL, mi->nMatId)); finalPolyMesh.Save(inputSceneNode, transform44f, options, 0.0); } AbcG::OPolyMeshSchema::Sample meshSample; AbcG::OPolyMeshSchema meshSchema; { ESS_PROFILE_SCOPE("AlembicPoints::saveCurrentFrameMeshes - save xforms, bbox, geo, topo"); //save out the mesh xForm //std::string xformName = mi->name + "Xfo"; AbcG::OXform xform(mJob->GetArchive().getTop(), mi->name, GetCurrentJob()->GetAnimatedTs()); AbcG::OXformSchema& xformSchema = xform.getSchema();//mi->xformSchema; std::string meshName = mi->name + "Shape"; AbcG::OPolyMesh mesh(xform, meshName, GetCurrentJob()->GetAnimatedTs()); meshSchema = mesh.getSchema(); AbcG::XformSample xformSample; Matrix3 alembicMatrix; alembicMatrix.IdentityMatrix(); alembicMatrix.SetTrans(Point3(-10000.0f, -10000.0f, -10000.0f)); Abc::M44d iMatrix; ConvertMaxMatrixToAlembicMatrix(alembicMatrix, iMatrix); xformSample.setMatrix(iMatrix); xformSchema.set(xformSample); //update the archive bounding box Abc::Box3d bbox; bbox.min = finalPolyMesh.bbox.min * iMatrix; bbox.max = finalPolyMesh.bbox.max * iMatrix; mJob->GetArchiveBBox().extendBy(bbox); //save out the mesh data meshSample.setPositions(Abc::P3fArraySample(finalPolyMesh.posVec)); meshSample.setSelfBounds(finalPolyMesh.bbox); meshSchema.getChildBoundsProperty().set(finalPolyMesh.bbox); meshSample.setFaceCounts(Abc::Int32ArraySample(finalPolyMesh.mFaceCountVec)); meshSample.setFaceIndices(Abc::Int32ArraySample(finalPolyMesh.mFaceIndicesVec)); } if(mJob->GetOption("validateMeshTopology")){ ESS_PROFILE_SCOPE("AlembicPoints::saveCurrentFrameMeshes - validateMeshTopology"); mJob->mMeshErrors += validateAlembicMeshTopo(finalPolyMesh.mFaceCountVec, finalPolyMesh.mFaceIndicesVec, mi->name); } if(mJob->GetOption("exportNormals")){ ESS_PROFILE_SCOPE("AlembicPoints::saveCurrentFrameMeshes - exportNormals"); AbcG::ON3fGeomParam::Sample normalSample; normalSample.setScope(AbcG::kFacevaryingScope); normalSample.setVals(Abc::N3fArraySample(finalPolyMesh.mIndexedNormals.values)); normalSample.setIndices(Abc::UInt32ArraySample(finalPolyMesh.mIndexedNormals.indices)); meshSample.setNormals(normalSample); } if(mJob->GetOption("exportMaterialIds")){ ESS_PROFILE_SCOPE("AlembicPoints::saveCurrentFrameMeshes - exportMaterialIds"); Abc::OUInt32ArrayProperty mMatIdProperty = Abc::OUInt32ArrayProperty(meshSchema, ".materialids", meshSchema.getMetaData(), mJob->GetAnimatedTs()); mMatIdProperty.set(Abc::UInt32ArraySample(finalPolyMesh.mMatIdIndexVec)); for ( facesetmap_it it=finalPolyMesh.mFaceSets.begin(); it != finalPolyMesh.mFaceSets.end(); it++) { std::stringstream nameStream; int nMaterialId = it->first+1; nameStream<<it->second.name<<"_"<<nMaterialId; std::vector<Abc::int32_t>& faceSetVec = it->second.faceIds; AbcG::OFaceSet faceSet = meshSchema.createFaceSet(nameStream.str()); AbcG::OFaceSetSchema::Sample faceSetSample(Abc::Int32ArraySample(&faceSetVec.front(), faceSetVec.size())); faceSet.getSchema().set(faceSetSample); } } if(mJob->GetOption("exportUVs")){ //TODO... } { ESS_PROFILE_SCOPE("AlembicPoints::saveCurrentFrameMeshes meshSchema.set"); meshSchema.set(meshSample); } if(mi->bNeedDelete){ delete mi->pMesh; mi->bNeedDelete = FALSE; } mi->pMesh = NULL; } } mMeshesToSaveForCurrentFrame.clear(); }
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; }
AlembicPoints::meshInfo AlembicPoints::CacheShapeMesh(Mesh* pShapeMesh, BOOL bNeedDelete, Matrix3 meshTM, int nMatId, int particleId, TimeValue ticks, ShapeType &type, Abc::uint16_t &instanceId, float &animationTime) { ESS_PROFILE_FUNC(); type = ShapeType_Instance; //animationTime = 0; //Mesh* pShapeMesh = pExt->GetParticleShapeByIndex(particleId); if(pShapeMesh->getNumFaces() == 0 || pShapeMesh->getNumVerts() == 0){ meshInfo mi; return mi; } meshDigests digests; { ESS_PROFILE_SCOPE("AlembicPoints::CacheShapeMesh - compute hash"); AbcU::MurmurHash3_x64_128( pShapeMesh->verts, pShapeMesh->numVerts * sizeof(Point3), sizeof(Point3), digests.Vertices.words ); AbcU::MurmurHash3_x64_128( pShapeMesh->faces, pShapeMesh->numFaces * sizeof(Face), sizeof(Face), digests.Faces.words ); if(mJob->GetOption("exportMaterialIds")){ std::vector<MtlID> matIds; if(nMatId < 0){ matIds.reserve(pShapeMesh->getNumFaces()); for(int i=0; i<pShapeMesh->getNumFaces(); i++){ matIds.push_back(pShapeMesh->getFaceMtlIndex(i)); } } else{ matIds.push_back(nMatId); } AbcU::MurmurHash3_x64_128( &matIds[0], matIds.size() * sizeof(MtlID), sizeof(MtlID), digests.MatIds.words ); } if(mJob->GetOption("exportUVs")){ //TODO... } } mTotalShapeMeshes++; meshInfo currShapeInfo; faceVertexHashToShapeMap::iterator it = mShapeMeshCache.find(digests); if( it != mShapeMeshCache.end() ){ currShapeInfo = it->second; } else{ meshInfo& mi = mShapeMeshCache[digests]; mi.pMesh = pShapeMesh; mi.bbox = computeBoundingBox(pShapeMesh); mi.nMatId = nMatId; std::stringstream nameStream; nameStream<< EC_MCHAR_to_UTF8( mMaxNode->GetName() ) <<"_"; nameStream<<"InstanceMesh"<<mNumShapeMeshes; mi.name=nameStream.str(); mi.bNeedDelete = bNeedDelete; mi.meshTM = meshTM; mi.nMeshInstanceId = mNumShapeMeshes; currShapeInfo = mi; mNumShapeMeshes++; mMeshesToSaveForCurrentFrame.push_back(&mi); //ESS_LOG_WARNING("ticks: "<<ticks<<" particleId: "<<particleId); //ESS_LOG_WARNING("Adding shape with hash("<<vertexDigest.str()<<", "<<faceDigest.str()<<") \n auto assigned name "<<mi.name <<" efficiency:"<<(double)mNumShapeMeshes/mTotalShapeMeshes); } instanceId = currShapeInfo.nMeshInstanceId; // { // ESS_PROFILE_SCOPE("CacheShapeMesh push_back instance name"); //std::string pathName("/"); //pathName += currShapeInfo.name; //instanceId = FindInstanceName(pathName); //if (instanceId == USHRT_MAX){ // mInstanceNames.push_back(pathName); // instanceId = (Abc::uint16_t)mInstanceNames.size()-1; //} // } return currShapeInfo; }