MObject readNurbs(double iFrame, Alembic::AbcGeom::INuPatch & iNode, MObject & iObject) { MStatus status; MObject obj; Alembic::AbcGeom::INuPatchSchema schema = iNode.getSchema(); // no interpolation for now Alembic::AbcCoreAbstract::index_t index, ceilIndex; getWeightAndIndex(iFrame, schema.getTimeSampling(), schema.getNumSamples(), index, ceilIndex); Alembic::AbcGeom::INuPatchSchema::Sample samp; schema.get(samp, Alembic::Abc::ISampleSelector(index)); Alembic::Abc::P3fArraySamplePtr pos = samp.getPositions(); Alembic::Abc::FloatArraySamplePtr weights = samp.getPositionWeights(); MString surfaceName(iNode.getName().c_str()); unsigned int degreeU = samp.getUOrder() - 1; unsigned int degreeV = samp.getVOrder() - 1; unsigned int numCVInU = samp.getNumU(); unsigned int numCVInV = samp.getNumV(); // cv points unsigned int numCV = numCVInU*numCVInV; unsigned int curPos = 0; MPointArray controlVertices; controlVertices.setLength(numCV); for (unsigned int v = 0; v < numCVInV; ++v) { for (unsigned int u = 0; u < numCVInU; ++u, ++curPos) { unsigned int mayaIndex = u * numCVInV + (numCVInV - v - 1); MPoint pt((*pos)[curPos].x, (*pos)[curPos].y, (*pos)[curPos].z); if (weights) { pt.w = (*weights)[curPos]; } // go from u,v order to reversed v, u order controlVertices.set(pt, mayaIndex); } } // Nurbs form // Alemblic file does not record the form of nurb surface, we get the form // by checking the CV data. If the first degree number CV overlap the last // degree number CV, then the form is kPeriodic. If only the first CV overlaps // the last CV, then the form is kClosed. MFnNurbsSurface::Form formU = MFnNurbsSurface::kPeriodic; MFnNurbsSurface::Form formV = MFnNurbsSurface::kPeriodic; // Check all curves bool notOpen = true; for (unsigned int v = 0; notOpen && v < numCVInV; v++) { for (unsigned int u = 0; u < degreeU; u++) { unsigned int firstIndex = u * numCVInV + (numCVInV - v - 1); unsigned int lastPeriodicIndex = (numCVInU - degreeU + u) * numCVInV + (numCVInV - v - 1); if (!controlVertices[firstIndex].isEquivalent(controlVertices[lastPeriodicIndex])) { formU = MFnNurbsSurface::kOpen; notOpen = false; break; } } } if (formU == MFnNurbsSurface::kOpen) { formU = MFnNurbsSurface::kClosed; for (unsigned int v = 0; v < numCVInV; v++) { unsigned int lastUIndex = (numCVInU - 1) * numCVInV + (numCVInV - v - 1); if (! controlVertices[numCVInV-v-1].isEquivalent(controlVertices[lastUIndex])) { formU = MFnNurbsSurface::kOpen; break; } } } notOpen = true; for (unsigned int u = 0; notOpen && u < numCVInU; u++) { for (unsigned int v = 0; v < degreeV; v++) { unsigned int firstIndex = u * numCVInV + (numCVInV - v - 1); unsigned int lastPeriodicIndex = u * numCVInV + (degreeV - v - 1); //numV - (numV - vDegree + v) - 1; if (!controlVertices[firstIndex].isEquivalent(controlVertices[lastPeriodicIndex])) { formV = MFnNurbsSurface::kOpen; notOpen = false; break; } } } if (formV == MFnNurbsSurface::kOpen) { formV = MFnNurbsSurface::kClosed; for (unsigned int u = 0; u < numCVInU; u++) { if (! controlVertices[u * numCVInV + (numCVInV-1)].isEquivalent(controlVertices[u * numCVInV])) { formV = MFnNurbsSurface::kOpen; break; } } } Alembic::Abc::FloatArraySamplePtr uKnot = samp.getUKnot(); Alembic::Abc::FloatArraySamplePtr vKnot = samp.getVKnot(); unsigned int numKnotsInU = static_cast<unsigned int>(uKnot->size() - 2); MDoubleArray uKnotSequences; uKnotSequences.setLength(numKnotsInU); for (unsigned int i = 0; i < numKnotsInU; ++i) { uKnotSequences.set((*uKnot)[i+1], i); } unsigned int numKnotsInV = static_cast<unsigned int>(vKnot->size() - 2); MDoubleArray vKnotSequences; vKnotSequences.setLength(numKnotsInV); for (unsigned int i = 0; i < numKnotsInV; i++) { vKnotSequences.set((*vKnot)[i+1], i); } // Node creation try the API first MFnNurbsSurface mFn; obj = mFn.create(controlVertices, uKnotSequences, vKnotSequences, degreeU, degreeV, formU, formV, true, iObject, &status); // something went wrong, try open/open create if (status != MS::kSuccess && (formU != MFnNurbsSurface::kOpen || formV != MFnNurbsSurface::kOpen)) { obj = mFn.create(controlVertices, uKnotSequences, vKnotSequences, degreeU, degreeV, MFnNurbsSurface::kOpen, MFnNurbsSurface::kOpen, true, iObject, &status); } if (status == MS::kSuccess) { mFn.setName(surfaceName); } else { MString errorMsg = "Could not create Nurbs Surface: "; errorMsg += surfaceName; MGlobal::displayError(errorMsg); } trimSurface(samp, mFn); return obj; }