void MeshPrimitive::addPrimitiveVariable( const std::string &name, const IECore::PrimitiveVariable &primVar ) { if ( primVar.interpolation==IECore::PrimitiveVariable::Vertex || primVar.interpolation==IECore::PrimitiveVariable::Varying ) { if ( name == "P" ) { // update the bounding box. m_memberData->bound.makeEmpty(); IECore::ConstV3fVectorDataPtr points = IECore::runTimeCast< IECore::V3fVectorData >( primVar.data ); if ( points ) { const std::vector<Imath::V3f> &p = points->readable(); for( unsigned int i=0; i<p.size(); i++ ) { m_memberData->bound.extendBy( p[i] ); } } } MemberData::ToFaceVaryingConverter primVarConverter( m_memberData->vertIds ); // convert to facevarying IECore::DataPtr newData = IECore::despatchTypedData< MemberData::ToFaceVaryingConverter, IECore::TypeTraits::IsVectorTypedData >( primVar.data, primVarConverter ); addVertexAttribute( name, newData ); } else if ( primVar.interpolation==IECore::PrimitiveVariable::FaceVarying ) { addVertexAttribute( name, primVar.data ); } else if ( primVar.interpolation==IECore::PrimitiveVariable::Constant ) { addUniformAttribute( name, primVar.data ); } }
bool ToMayaMeshConverter::doConversion( IECore::ConstObjectPtr from, MObject &to, IECore::ConstCompoundObjectPtr operands ) const { MStatus s; IECore::ConstMeshPrimitivePtr mesh = IECore::runTimeCast<const IECore::MeshPrimitive>( from ); assert( mesh ); if ( !mesh->arePrimitiveVariablesValid() ) { return false; } MFloatPointArray vertexArray; MIntArray polygonCounts; MIntArray polygonConnects; MFnMesh fnMesh; int numVertices = 0; IECore::PrimitiveVariableMap::const_iterator it = mesh->variables.find("P"); if ( it != mesh->variables.end() ) { /// \todo Employ some M*Array converters to simplify this IECore::ConstV3fVectorDataPtr p = IECore::runTimeCast<const IECore::V3fVectorData>(it->second.data); if (p) { numVertices = p->readable().size(); vertexArray.setLength( numVertices ); for (int i = 0; i < numVertices; i++) { vertexArray[i] = IECore::convert<MFloatPoint, Imath::V3f>( p->readable()[i] ); } } else { IECore::ConstV3dVectorDataPtr p = IECore::runTimeCast<const IECore::V3dVectorData>(it->second.data); if (p) { numVertices = p->readable().size(); vertexArray.setLength( numVertices ); for (int i = 0; i < numVertices; i++) { vertexArray[i] = IECore::convert<MFloatPoint, Imath::V3d>( p->readable()[i] ); } } else { // "P" is not convertible to an array of "points" return false; } } } IECore::ConstIntVectorDataPtr verticesPerFace = mesh->verticesPerFace(); assert( verticesPerFace ); int numPolygons = verticesPerFace->readable().size(); polygonCounts.setLength( numPolygons ); for (int i = 0; i < numPolygons; i++) { polygonCounts[i] = verticesPerFace->readable()[i]; } IECore::ConstIntVectorDataPtr vertexIds = mesh->vertexIds(); assert( vertexIds ); int numPolygonConnects = vertexIds->readable().size(); polygonConnects.setLength( numPolygonConnects ); for (int i = 0; i < numPolygonConnects; i++) { polygonConnects[i] = vertexIds->readable()[i]; } MObject mObj = fnMesh.create( numVertices, numPolygons, vertexArray, polygonCounts, polygonConnects, to, &s ); if (!s) { return false; } it = mesh->variables.find("N"); if ( it != mesh->variables.end() ) { if (it->second.interpolation == IECore::PrimitiveVariable::FaceVarying ) { /// \todo Employ some M*Array converters to simplify this MVectorArray vertexNormalsArray; IECore::ConstV3fVectorDataPtr n = IECore::runTimeCast<const IECore::V3fVectorData>(it->second.data); if (n) { int numVertexNormals = n->readable().size(); vertexNormalsArray.setLength( numVertexNormals ); for (int i = 0; i < numVertexNormals; i++) { vertexNormalsArray[i] = IECore::convert<MVector, Imath::V3f>( n->readable()[i] ); } } else { IECore::ConstV3dVectorDataPtr n = IECore::runTimeCast<const IECore::V3dVectorData>(it->second.data); if (n) { int numVertexNormals = n->readable().size(); vertexNormalsArray.setLength( numVertexNormals ); for (int i = 0; i < numVertexNormals; i++) { vertexNormalsArray[i] = IECore::convert<MVector, Imath::V3d>( n->readable()[i] ); } } else { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"N\" has unsupported type \"%s\"." ) % it->second.data->typeName() ); } } if ( vertexNormalsArray.length() ) { MStatus status; MItMeshPolygon itPolygon( mObj, &status ); if( status != MS::kSuccess ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "Failed to create mesh iterator" ); } unsigned v = 0; MIntArray vertexIds; MIntArray faceIds; for ( ; !itPolygon.isDone(); itPolygon.next() ) { for ( v=0; v < itPolygon.polygonVertexCount(); ++v ) { faceIds.append( itPolygon.index() ); vertexIds.append( itPolygon.vertexIndex( v ) ); } } if( !fnMesh.setFaceVertexNormals( vertexNormalsArray, faceIds, vertexIds ) ) { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "Setting normals failed" ); } } } else { IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "PrimitiveVariable \"N\" has unsupported interpolation (expected FaceVarying)." ); } } bool haveDefaultUVs = false; IECore::PrimitiveVariableMap::const_iterator sIt = mesh->variables.find( "s" ); IECore::RefCountedPtr sDataRef = ( sIt == mesh->variables.end() ) ? 0 : static_cast<IECore::RefCountedPtr>( sIt->second.data ); /// Add named UV sets std::set< std::string > uvSets; for ( it = mesh->variables.begin(); it != mesh->variables.end(); ++it ) { const std::string &sName = it->first; size_t suffixOffset = sName.rfind( "_s" ); if ( ( suffixOffset != std::string::npos) && ( suffixOffset == sName.length() - 2 ) ) { std::string uvSetNameStr = sName.substr( 0, suffixOffset ); if ( uvSetNameStr.size() ) { MString uvSetName = uvSetNameStr.c_str(); std::string tName = uvSetNameStr + "_t"; std::string stIdName = uvSetNameStr + "Indices"; addUVSet( fnMesh, polygonCounts, mesh, sName, tName, stIdName, &uvSetName ); uvSets.insert( uvSetNameStr ); if ( sDataRef == static_cast<IECore::RefCountedPtr>( it->second.data ) ) { haveDefaultUVs = true; } } } } /// Add default UV set if it isn't just a reference to a named set if ( !haveDefaultUVs ) { addUVSet( fnMesh, polygonCounts, mesh, "s", "t", "stIndices" ); } // We do the search again, but looking for primvars ending "_t", so we can catch cases where either "UVSETNAME_s" or "UVSETNAME_t" is present, but not both, taking care // not to attempt adding any duplicate sets for ( it = mesh->variables.begin(); it != mesh->variables.end(); ++it ) { const std::string &tName = it->first; size_t suffixOffset = tName.rfind( "_t" ); if ( ( suffixOffset != std::string::npos) && ( suffixOffset == tName.length() - 2 ) ) { std::string uvSetNameStr = tName.substr( 0, suffixOffset ); if ( uvSetNameStr.size() && uvSets.find( uvSetNameStr ) == uvSets.end() ) { MString uvSetName = uvSetNameStr.c_str(); std::string sName = uvSetNameStr + "_s"; std::string stIdName = uvSetNameStr + "Indices"; addUVSet( fnMesh, polygonCounts, mesh, sName, tName, stIdName, &uvSetName ); uvSets.insert( uvSetNameStr ); } } } /// If we're making a mesh node (rather than a mesh data) then make sure it belongs /// to the default shading group and add the ieMeshInterpolation attribute. MObject oMesh = fnMesh.object(); if( oMesh.apiType()==MFn::kMesh ) { assignDefaultShadingGroup( oMesh ); setMeshInterpolationAttribute( oMesh, mesh->interpolation() ); } /// \todo Other primvars, e.g. vertex color ("Cs") return true; }
bool ToMayaCurveConverter::doConversion( IECore::ConstObjectPtr from, MObject &to, IECore::ConstCompoundObjectPtr operands ) const { MStatus s; IECore::ConstCurvesPrimitivePtr curves = IECore::runTimeCast<const IECore::CurvesPrimitive>( from ); assert( curves ); if ( !curves->arePrimitiveVariablesValid() || !curves->numCurves() ) { return false; } int curveIndex = indexParameter()->getNumericValue(); if( curveIndex < 0 || curveIndex >= (int)curves->numCurves() ) { IECore::msg( IECore::Msg::Warning,"ToMayaCurveConverter::doConversion", boost::format( "Invalid curve index \"%d\"") % curveIndex ); return false; } IECore::ConstV3fVectorDataPtr p = curves->variableData< IECore::V3fVectorData >( "P", IECore::PrimitiveVariable::Vertex ); if( !p ) { IECore::msg( IECore::Msg::Warning,"ToMayaCurveConverter::doConversion", "Curve has no \"P\" data" ); return false; } const std::vector<int>& verticesPerCurve = curves->verticesPerCurve()->readable(); int curveBase = 0; for( int i=0; i<curveIndex; ++i ) { curveBase += verticesPerCurve[i]; } MPointArray vertexArray; int numVertices = verticesPerCurve[curveIndex]; int cvOffset = 0; if( curves->basis() != IECore::CubicBasisf::linear() && !curves->periodic() ) { // Maya implicitly duplicates end points, so they're explicitly duplicated in the CurvePrimitives. // We need to remove those duplicates when converting back to Maya. Remove 2 cvs at start, 2 at end. if( numVertices < 8 ) { IECore::msg( IECore::Msg::Warning,"ToMayaCurveConverter::doConversion", "The Curve Primitive does not have enough CVs to be converted into a Maya Curve. Needs at least 8." ); return false; } cvOffset = 2; } const std::vector<Imath::V3f>& pts = p->readable(); // triple up the start points for cubic periodic curves: if( curves->periodic() && curves->basis() != IECore::CubicBasisf::linear() ) { vertexArray.append( IECore::convert<MPoint, Imath::V3f>( pts[curveBase] ) ); vertexArray.append( vertexArray[0] ); } for( int i = cvOffset; i < numVertices-cvOffset; ++i ) { vertexArray.append( IECore::convert<MPoint, Imath::V3f>( pts[i + curveBase] ) ); } // if the curve is periodic, the first N cvs must be identical to the last N cvs, where N is the degree // of the curve: if( curves->periodic() ) { if( curves->basis() == IECore::CubicBasisf::linear() ) { // linear: N = 1 vertexArray.append( vertexArray[0] ); } else { // cubic: N = 3 vertexArray.append( vertexArray[0] ); vertexArray.append( vertexArray[1] ); vertexArray.append( vertexArray[2] ); } } unsigned vertexArrayLength = vertexArray.length(); MDoubleArray knotSequences; if( curves->basis() == IECore::CubicBasisf::linear() ) { for( unsigned i=0; i < vertexArrayLength; ++i ) { knotSequences.append( i ); } } else { if( curves->periodic() ) { // Periodic curve, knots must be spaced out. knotSequences.append( -1 ); for( unsigned i=0; i < vertexArrayLength+1; ++i ) { knotSequences.append( i ); } } else { // For a cubic curve, the first three and last three knots must be duplicated for the curve start/end to start at the first/last CV. knotSequences.append( 0 ); knotSequences.append( 0 ); for( unsigned i=0; i < vertexArrayLength-2; ++i ) { knotSequences.append( i ); } knotSequences.append( vertexArrayLength-3 ); knotSequences.append( vertexArrayLength-3 ); } } MFnNurbsCurve fnCurve; fnCurve.create( vertexArray, knotSequences, curves->basis() == IECore::CubicBasisf::linear() ? 1 : 3, curves->periodic() ? MFnNurbsCurve::kPeriodic : MFnNurbsCurve::kOpen, false, false, to, &s ); if (!s) { IECore::msg( IECore::Msg::Warning,"ToMayaCurveConverter::doConversion", s.errorString().asChar() ); return false; } return true; }