MSelectionList convertMIntArrToMselList( MIntArray& intArr, MDagPath& dPath, MFn::Type kCompType ) { MFnSingleIndexedComponent singleIndexCompFn; // create MObjet componenet by sigleIndexComponent MObject components = singleIndexCompFn.create(kCompType); singleIndexCompFn.addElements( intArr ); MSelectionList compSelList; compSelList.add( dPath, components ); return compSelList; }
//--------------------------------------------- void IV_makeSelection(void* data) //--------------------------------------------- { BPT_InsertVtx* nodePtr = (BPT_InsertVtx*) data; MEventMessage::removeCallback(nodePtr->eID); MDagPath meshPath; nodePtr->getMeshPath(meshPath); if( !(meshPath.apiType() == MFn::kInvalid) && nodePtr->validIndices.length() != 0) //zur Sicherheit, sollte aber eigentlich nicht mueueglich sein { MFnSingleIndexedComponent compFn; MFn::Type type = MFn::kInvalid; if(nodePtr->validIndices[0] == 1) type = MFn::kMeshEdgeComponent; else if(nodePtr->validIndices[0] == 2) type = MFn::kMeshPolygonComponent; else if(nodePtr->validIndices[0] == 3) type = MFn::kMeshVertComponent; assert(type != MFn::kInvalid); //flag wieder entfernen nodePtr->validIndices.remove(0); MSelectionList compList, current; MObject comps = compFn.create(type); compFn.addElements(nodePtr->validIndices); compList.add(meshPath,comps); compList.add(nodePtr->thisMObject()); // MGlobal::getActiveSelectionList(current); MGlobal::setActiveSelectionList(compList, MGlobal::kAddToList); // MGlobal::setActiveSelectionList(current,MGlobal::kAddToList); } }
MStatus splitUV::pruneUVs( MIntArray& validUVIndices ) // // Description: // // This method will remove any invalid UVIds from the component list and UVId array. // The benefit of this is to reduce the amount of extra processing that the node would // have to perform. It will result in less iterations through the mesh as there are // less UVs to search for. // { MStatus status; unsigned i; MIntArray validUVIds; for( i = 0; i < validUVIndices.length(); i++ ) { int uvIndex = validUVIndices[i]; validUVIds.append( fSelUVs[uvIndex] ); } // Replace the local int array of UVIds // fSelUVs.clear(); fSelUVs = validUVIds; // Build the list of valid components // MFnSingleIndexedComponent compFn; compFn.create( MFn::kMeshMapComponent, &status ); MCheckStatus( status, "compFn.create( MFn::kMeshMapComponent )" ); status = compFn.addElements( validUVIds ); MCheckStatus( status, "compFn.addElements( validUVIds )" ); MObject component = compFn.object(); // Replace the component list // MFnComponentListData compListFn; compListFn.create(); status = compListFn.add( component ); MCheckStatus( status, "compListFn.add( component )" ); fComponentList = compListFn.object(); return status; }
// ouput the MselectList of VERTEX Component MSelectionList getVtxSelList( MDagPath& inDagPath, const int inCompArray[], int inCountArray ) { // vtx process // MSelectionList vtxSelList; // Create a MFnSingleIndexedComponent object of type kMeshVertComponent. MFnSingleIndexedComponent singleIndexCompFn; MObject components = singleIndexCompFn.create(MFn::kMeshVertComponent); MIntArray elementArray( inCompArray, inCountArray); // Add the element indices singleIndexCompFn.addElements(elementArray); // Add the element to the selection list. vtxSelList.add( inDagPath, components ); return vtxSelList; }
// ==================================== // Helper Functions // ==================================== // Create component groups void createComp(MFnMeshData &dataCreator, MFn::Type compType, unsigned compId, MIntArray &compList) { MStatus returnStatus; MFnSingleIndexedComponent comp; MObject compObj = comp.create(compType,&returnStatus); MWARNERR(returnStatus, "cannot create MFnSingleIndexedComponent"); returnStatus = comp.addElements(compList); MWARNERR(returnStatus, "Error in addElements() for MFnSingleIndexedComponent"); returnStatus = dataCreator.addObjectGroup(compId); MWARNERR(returnStatus, "Error in addObjectGroup()"); returnStatus = dataCreator.setObjectGroupComponent(compId, compObj); MWARNERR(returnStatus, "Error in setObjectGroupComponent()"); }
static bool _AssignMaterialFaceSet( const MObject& shadingEngine, const MDagPath& shapeDagPath, const VtIntArray& faceIndices) { MStatus status; // Create component object using single indexed // components, i.e. face indices. MFnSingleIndexedComponent compFn; MObject faceComp = compFn.create(MFn::kMeshPolygonComponent, &status); if (!status) { TF_RUNTIME_ERROR("Failed to create face component."); return false; } MIntArray mFaces; TF_FOR_ALL(fIdxIt, faceIndices) { mFaces.append(*fIdxIt); }
MStatus SelectRingToolCmd2::redoIt() { //MGlobal::displayInfo( "redoIt" ); MItMeshPolygon polyIter( selEdgeObject ); MItMeshEdge edgeIter( selEdgeObject, selEdgeComp ); //MFnSingleIndexedComponent si( selEdgeComp ); //MGlobal::displayInfo( MString("doing stuff on ") + selEdgeObject.fullPathName() + " " + si.element(0) ); MFnSingleIndexedComponent indexedCompFn; MObject newComponent; MSelectionList newSel; MIntArray edges; MIntArray faces; unsigned int i; const int initEdgeIndex = edgeIter.index(); int initFaceIndex; int prevIndex, lastIndex; int faceIndex, edgeIndex; int newFaceIndex, newEdgeIndex; int nInitEdgeVisits; MIntArray remainFaces; MIntArray remainEdges; if( selType == RING ) { nInitEdgeVisits = 0; // Push the face+edge combo on both sides // of the current edge onto the stack edgeIter.getConnectedFaces( faces ); if( faces.length() > 1 ) { remainFaces.append( faces[1] ); remainEdges.append( initEdgeIndex ); } initFaceIndex = faces[0]; remainFaces.append( initFaceIndex ); remainEdges.append( initEdgeIndex ); while( remainFaces.length() ) { // Pop the face and edge indices lastIndex = remainFaces.length() - 1; faceIndex = remainFaces[ lastIndex ]; edgeIndex = remainEdges[ lastIndex ]; remainFaces.remove( lastIndex ); remainEdges.remove( lastIndex ); // If the current edge the initial edge if( faceIndex == initFaceIndex && edgeIndex == initEdgeIndex ) { // Reached back to the initial edge, so the loop is closed if( ++nInitEdgeVisits == 2 ) break; } // Add edge to the new selection list if( selEdges ) { newComponent = indexedCompFn.create( MFn::kMeshEdgeComponent ); indexedCompFn.addElement( edgeIndex ); newSel.add( selEdgeObject, newComponent ); } // Add vertices to the new selection list if( selVertices ) { newComponent = indexedCompFn.create( MFn::kMeshVertComponent ); edgeIter.setIndex( edgeIndex, prevIndex ); indexedCompFn.addElement( edgeIter.index(0) ); indexedCompFn.addElement( edgeIter.index(1) ); newSel.add( selEdgeObject, newComponent ); } if( faceIndex != -1 ) // Not a boundary edge { // Add face to the new selection list if( selFaces ) { newComponent = indexedCompFn.create( MFn::kMeshPolygonComponent ); indexedCompFn.addElement( faceIndex ); newSel.add( selEdgeObject, newComponent ); } // Get edge opposite the current edge // newEdgeIndex = navigateFace( selEdgeObject, faceIndex, edgeIndex, OPPOSITE ); // Get the face on the other side of the opposite edge // edgeIter.setIndex( newEdgeIndex, prevIndex ); edgeIter.getConnectedFaces( faces ); newFaceIndex = -1; // Initialize to a boundary edge if( faces.length() > 1 ) newFaceIndex = (faceIndex == faces[0]) ? faces[1] : faces[0]; // Push face and edge onto list remainFaces.append( newFaceIndex ); remainEdges.append( newEdgeIndex ); } } } else // Ring { int reflEdgeIndex; int newReflEdgeIndex; int initReflEdgeIndex; MIntArray remainReflEdges; nInitEdgeVisits = 0; // Push the face+edge+reflect combo on both sides // of the current edge onto the stack //edgeIter.setIndex( initEdgeIndex, prevIndex ); edgeIter.getConnectedFaces( faces ); initFaceIndex = faces[0]; for( i=0; i < 2; i++ ) { remainFaces.append( initFaceIndex ); remainEdges.append( initEdgeIndex ); remainReflEdges.append( navigateFace( selEdgeObject, initFaceIndex, initEdgeIndex, (i == 0) ? PREVIOUS : NEXT ) ); } initReflEdgeIndex = remainReflEdges[1]; while( remainFaces.length() ) { // Pop the face, edge, and reflEdge indices lastIndex = remainFaces.length() - 1; faceIndex = remainFaces[ lastIndex ]; edgeIndex = remainEdges[ lastIndex ]; reflEdgeIndex = remainReflEdges[ lastIndex ]; remainFaces.remove( lastIndex ); remainEdges.remove( lastIndex ); remainReflEdges.remove( lastIndex ); //MGlobal::displayInfo( MString("Face: ") + faceIndex + " edge: " + edgeIndex + " reflEdgeIndex: " + reflEdgeIndex ); // If the current edge the initial edge if( faceIndex == initFaceIndex && edgeIndex == initEdgeIndex && reflEdgeIndex == initReflEdgeIndex ) { // Reached back to the initial edge, so the ring is closed if( ++nInitEdgeVisits == 2 ) break; } // Add edge to the new selection list if( selEdges ) { newComponent = indexedCompFn.create( MFn::kMeshEdgeComponent ); indexedCompFn.addElement( edgeIndex ); newSel.add( selEdgeObject, newComponent ); } // Add vertices to the new selection list if( selVertices ) { newComponent = indexedCompFn.create( MFn::kMeshVertComponent ); edgeIter.setIndex( edgeIndex, prevIndex ); indexedCompFn.addElement( edgeIter.index(0) ); indexedCompFn.addElement( edgeIter.index(1) ); newSel.add( selEdgeObject, newComponent ); } // Add face to the new selection list if( selFaces ) { newComponent = indexedCompFn.create( MFn::kMeshPolygonComponent ); indexedCompFn.addElement( faceIndex ); newSel.add( selEdgeObject, newComponent ); } // Get the face on opposite side of reflEdge edgeIter.setIndex( reflEdgeIndex, prevIndex ); edgeIter.getConnectedFaces( faces ); // Only if there are two faces can their be an opposite face if( faces.length() > 1 ) { newFaceIndex = (faceIndex == faces[0]) ? faces[1] : faces[0]; int edgePrev = navigateFace( selEdgeObject, newFaceIndex, reflEdgeIndex, PREVIOUS ); int edgeNext = navigateFace( selEdgeObject, newFaceIndex, reflEdgeIndex, NEXT ); // Determine which of the edges touches the original edge // edgeIter.setIndex( edgeIndex, prevIndex ); if( edgeIter.connectedToEdge( edgePrev ) ) { newEdgeIndex = edgePrev; newReflEdgeIndex = navigateFace( selEdgeObject, newFaceIndex, newEdgeIndex, PREVIOUS ); } else { newEdgeIndex = edgeNext; newReflEdgeIndex = navigateFace( selEdgeObject, newFaceIndex, newEdgeIndex, NEXT ); } // Push face, edge, and reflEdge onto list remainFaces.append( newFaceIndex ); remainEdges.append( newEdgeIndex ); remainReflEdges.append( newReflEdgeIndex ); } } } // Set the active selection to the one previous to edge loop selection MGlobal::setActiveSelectionList( prevSel, MGlobal::kReplaceList ); // Update this selection based on the list adjustment setting MGlobal::selectCommand( newSel, listAdjust ); return MS::kSuccess; }
bool ProceduralHolderUI::select( MSelectInfo &selectInfo, MSelectionList &selectionList, MPointArray &worldSpaceSelectPts ) const { MStatus s; // early out if we're not selectable. we always allow components to be selected if we're highlighted, // but we don't allow ourselves to be selected as a whole unless meshes are in the selection mask. // it's not ideal that we act like a mesh, but it's at least consistent with the drawing mask we use. if( selectInfo.displayStatus() != M3dView::kHilite ) { MSelectionMask meshMask( MSelectionMask::kSelectMeshes ); if( !selectInfo.selectable( meshMask ) ) { return false; } } // early out if we have no scene to draw ProceduralHolder *proceduralHolder = static_cast<ProceduralHolder *>( surfaceShape() ); IECoreGL::ConstScenePtr scene = proceduralHolder->scene(); if( !scene ) { return false; } // we want to perform the selection using an IECoreGL::Selector, so we // can avoid the performance penalty associated with using GL_SELECT mode. // that means we don't really want to call view.beginSelect(), but we have to // call it just to get the projection matrix for our own selection, because as far // as i can tell, there is no other way of getting it reliably. M3dView view = selectInfo.view(); view.beginSelect(); Imath::M44d projectionMatrix; glGetDoublev( GL_PROJECTION_MATRIX, projectionMatrix.getValue() ); view.endSelect(); view.beginGL(); glMatrixMode( GL_PROJECTION ); glLoadMatrixd( projectionMatrix.getValue() ); IECoreGL::Selector::Mode selectionMode = IECoreGL::Selector::IDRender; if( selectInfo.displayStatus() == M3dView::kHilite && !selectInfo.singleSelection() ) { selectionMode = IECoreGL::Selector::OcclusionQuery; } std::vector<IECoreGL::HitRecord> hits; { IECoreGL::Selector selector( Imath::Box2f( Imath::V2f( 0 ), Imath::V2f( 1 ) ), selectionMode, hits ); IECoreGL::State::bindBaseState(); selector.baseState()->bind(); scene->render( selector.baseState() ); if( selectInfo.displayStatus() != M3dView::kHilite ) { // we're not in component selection mode. we'd like to be able to select the procedural // object using the bounding box so we draw it too. MPlug pDrawBound( proceduralHolder->thisMObject(), ProceduralHolder::aDrawBound ); bool drawBound = true; pDrawBound.getValue( drawBound ); if( drawBound ) { IECoreGL::BoxPrimitive::renderWireframe( IECore::convert<Imath::Box3f>( proceduralHolder->boundingBox() ) ); } } } view.endGL(); if( !hits.size() ) { return false; } // iterate over the hits, converting them into components and also finding // the closest one. MIntArray componentIndices; float depthMin = std::numeric_limits<float>::max(); int depthMinIndex = -1; for( int i=0, e = hits.size(); i < e; i++ ) { if( hits[i].depthMin < depthMin ) { depthMin = hits[i].depthMin; depthMinIndex = componentIndices.length(); } ProceduralHolder::ComponentsMap::const_iterator compIt = proceduralHolder->m_componentsMap.find( hits[i].name.value() ); assert( compIt != proceduralHolder->m_componentsMap.end() ); componentIndices.append( compIt->second.first ); } assert( depthMinIndex >= 0 ); // figure out the world space location of the closest hit MDagPath camera; view.getCamera( camera ); MFnCamera fnCamera( camera.node() ); float near = fnCamera.nearClippingPlane(); float far = fnCamera.farClippingPlane(); float z = -1; if( fnCamera.isOrtho() ) { z = Imath::lerp( near, far, depthMin ); } else { // perspective camera - depth isn't linear so linearise to get z float a = far / ( far - near ); float b = far * near / ( near - far ); z = b / ( depthMin - a ); } MPoint localRayOrigin; MVector localRayDirection; selectInfo.getLocalRay( localRayOrigin, localRayDirection ); MMatrix localToCamera = selectInfo.selectPath().inclusiveMatrix() * camera.inclusiveMatrix().inverse(); MPoint cameraRayOrigin = localRayOrigin * localToCamera; MVector cameraRayDirection = localRayDirection * localToCamera; MPoint cameraIntersectionPoint = cameraRayOrigin + cameraRayDirection * ( -( z - near ) / cameraRayDirection.z ); MPoint worldIntersectionPoint = cameraIntersectionPoint * camera.inclusiveMatrix(); // turn the processed hits into appropriate changes to the current selection if( selectInfo.displayStatus() == M3dView::kHilite ) { // selecting components MFnSingleIndexedComponent fnComponent; MObject component = fnComponent.create( MFn::kMeshPolygonComponent, &s ); assert( s ); if( selectInfo.singleSelection() ) { fnComponent.addElement( componentIndices[depthMinIndex] ); } else { fnComponent.addElements( componentIndices ); } MSelectionList items; items.add( selectInfo.multiPath(), component ); selectInfo.addSelection( items, worldIntersectionPoint, selectionList, worldSpaceSelectPts, MSelectionMask::kSelectMeshFaces, true ); } else { // selecting objects MSelectionList item; item.add( selectInfo.selectPath() ); selectInfo.addSelection( item, worldIntersectionPoint, selectionList, worldSpaceSelectPts, MSelectionMask::kSelectMeshes, false ); } return true; }
//----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- MStatus CVstSelectCoincidentFacesCmd::DoSelect() { MSelectionList meshList; GetSpecifiedMeshes( meshList ); MSelectionList coincidentList; MDagPath mDagPath; MObject cObj; MPointArray points; MIntArray iIndexes; MIntArray jIndexes; uint iCount; bool addI; bool same; bool foundVertex; double tolerance( MPoint_kTol ); if ( m_undo.ArgDatabase().isFlagSet( kOptTolerance ) ) { MDistance optTolerance; m_undo.ArgDatabase().getFlagArgument( kOptTolerance, 0U, optTolerance ); tolerance = optTolerance.as( MDistance::internalUnit() ); } for ( MItSelectionList sIt( meshList ); !sIt.isDone(); sIt.next() ) { if ( !sIt.getDagPath( mDagPath, cObj ) ) continue; MFnSingleIndexedComponent sFn; MObject sObj( sFn.create( MFn::kMeshPolygonComponent ) ); MFnMesh meshFn( mDagPath ); meshFn.getPoints( points ); if ( !sIt.hasComponents() ) { const uint nFaces( meshFn.numPolygons() ); for ( uint i( 0U ); i != nFaces; ++i ) { meshFn.getPolygonVertices( i, iIndexes ); iCount = iIndexes.length(); addI = false; for ( uint j( i + 1 ); j < nFaces; ++j ) { meshFn.getPolygonVertices( j, jIndexes ); if ( jIndexes.length() == iCount ) { same = true; for ( uint k( 0U ); k != iCount; ++k ) { foundVertex = false; const MPoint &kPoint( points[ iIndexes[ k ] ] ); for ( uint l( 0U ); l < iCount; ++l ) { if ( kPoint.isEquivalent( points[ jIndexes[ l ] ], tolerance ) ) { foundVertex = true; break; } } if ( !foundVertex ) { same = false; break; } } if ( same ) { addI = true; sFn.addElement( j ); } } } if ( addI ) { sFn.addElement( i ); } } } else { MFnSingleIndexedComponent cFn( cObj ); MIntArray cA; MFnSingleIndexedComponent( cObj ).getElements( cA ); const uint nFaces( cA.length() ); for ( uint i( 0U ); i != nFaces; ++i ) { meshFn.getPolygonVertices( cA[ i ], iIndexes ); iCount = iIndexes.length(); addI = false; for ( uint j( i + 1U ); j < nFaces; ++j ) { meshFn.getPolygonVertices( cA[ j ], jIndexes ); if ( jIndexes.length() == iCount ) { same = true; for ( uint k( 0U ); k != iCount; ++k ) { foundVertex = false; const MPoint &kPoint( points[ iIndexes[ k ] ] ); for ( uint l( 0U ); l < iCount; ++l ) { if ( kPoint.isEquivalent( points[ jIndexes[ l ] ], tolerance ) ) { foundVertex = true; break; } } if ( !foundVertex ) { same = false; break; } } if ( same ) { addI = true; sFn.addElement( cA[ j ] ); } } } if ( addI ) { sFn.addElement( cA[ i ] ); } } } if ( sFn.elementCount() > 0 ) { coincidentList.add( mDagPath, sObj ); } else { MSelectionList tmpList; tmpList.add( mDagPath, cObj ); MStringArray tmpA; tmpList.getSelectionStrings( tmpA ); minfo << "No coincident faces on:"; for ( uint i( 0U ); i != tmpA.length(); ++i ) { minfo << " " << tmpA[ i ]; } minfo << std::endl; } } if ( coincidentList.length() ) { MGlobal::setActiveSelectionList( coincidentList ); MStringArray tmpA; coincidentList.getSelectionStrings( tmpA ); setResult( tmpA ); } else { if ( meshList.length() > 0U ) { minfo << "No coincident faces found" << std::endl; } } return MS::kSuccess; }
MayaMeshWriter::MayaMeshWriter(MDagPath & iDag, Alembic::Abc::OObject & iParent, Alembic::Util::uint32_t iTimeIndex, const JobArgs & iArgs, GetMembersMap& gmMap) : mNoNormals(iArgs.noNormals), mWriteUVs(iArgs.writeUVs), mWriteColorSets(iArgs.writeColorSets), mWriteUVSets(iArgs.writeUVSets), mIsGeometryAnimated(false), mDagPath(iDag) { MStatus status = MS::kSuccess; MFnMesh lMesh( mDagPath, &status ); if ( !status ) { MGlobal::displayError( "MFnMesh() failed for MayaMeshWriter" ); } // intermediate objects aren't translated MObject surface = iDag.node(); if (iTimeIndex != 0 && util::isAnimated(surface)) { mIsGeometryAnimated = true; } else { iTimeIndex = 0; } std::vector<float> uvs; std::vector<Alembic::Util::uint32_t> indices; std::string uvSetName; MString name = lMesh.name(); name = util::stripNamespaces(name, iArgs.stripNamespace); // check to see if this poly has been tagged as a SubD MPlug plug = lMesh.findPlug("SubDivisionMesh"); if ( !plug.isNull() && plug.asBool() ) { Alembic::AbcGeom::OSubD obj(iParent, name.asChar(), iTimeIndex); mSubDSchema = obj.getSchema(); Alembic::AbcGeom::OV2fGeomParam::Sample uvSamp; if (mWriteUVs || mWriteUVSets) { getUVs(uvs, indices, uvSetName); if (!uvs.empty()) { if (!uvSetName.empty()) { mSubDSchema.setUVSourceName(uvSetName); } uvSamp.setScope( Alembic::AbcGeom::kFacevaryingScope ); uvSamp.setVals(Alembic::AbcGeom::V2fArraySample( (const Imath::V2f *) &uvs.front(), uvs.size() / 2)); if (!indices.empty()) { uvSamp.setIndices(Alembic::Abc::UInt32ArraySample( &indices.front(), indices.size())); } } } Alembic::Abc::OCompoundProperty cp; Alembic::Abc::OCompoundProperty up; if (AttributesWriter::hasAnyAttr(lMesh, iArgs)) { cp = mSubDSchema.getArbGeomParams(); up = mSubDSchema.getUserProperties(); } mAttrs = AttributesWriterPtr(new AttributesWriter(cp, up, obj, lMesh, iTimeIndex, iArgs)); writeSubD(uvSamp); } else { Alembic::AbcGeom::OPolyMesh obj(iParent, name.asChar(), iTimeIndex); mPolySchema = obj.getSchema(); Alembic::AbcGeom::OV2fGeomParam::Sample uvSamp; if (mWriteUVs || mWriteUVSets) { getUVs(uvs, indices, uvSetName); if (!uvs.empty()) { if (!uvSetName.empty()) { mPolySchema.setUVSourceName(uvSetName); } uvSamp.setScope( Alembic::AbcGeom::kFacevaryingScope ); uvSamp.setVals(Alembic::AbcGeom::V2fArraySample( (const Imath::V2f *) &uvs.front(), uvs.size() / 2)); if (!indices.empty()) { uvSamp.setIndices(Alembic::Abc::UInt32ArraySample( &indices.front(), indices.size())); } } } Alembic::Abc::OCompoundProperty cp; Alembic::Abc::OCompoundProperty up; if (AttributesWriter::hasAnyAttr(lMesh, iArgs)) { cp = mPolySchema.getArbGeomParams(); up = mPolySchema.getUserProperties(); } // set the rest of the props and write to the writer node mAttrs = AttributesWriterPtr(new AttributesWriter(cp, up, obj, lMesh, iTimeIndex, iArgs)); writePoly(uvSamp); } if (mWriteColorSets) { MStringArray colorSetNames; lMesh.getColorSetNames(colorSetNames); if (colorSetNames.length() > 0) { // Create the color sets compound prop Alembic::Abc::OCompoundProperty arbParams; if (mPolySchema.valid()) { arbParams = mPolySchema.getArbGeomParams(); } else { arbParams = mSubDSchema.getArbGeomParams(); } std::string currentColorSet = lMesh.currentColorSetName().asChar(); for (unsigned int i=0; i < colorSetNames.length(); ++i) { // Create an array property for each color set std::string colorSetPropName = colorSetNames[i].asChar(); Alembic::AbcCoreAbstract::MetaData md; if (currentColorSet == colorSetPropName) { md.set("mayaColorSet", "1"); } else { md.set("mayaColorSet", "0"); } if (lMesh.getColorRepresentation(colorSetNames[i]) == MFnMesh::kRGB) { Alembic::AbcGeom::OC3fGeomParam colorProp(arbParams, colorSetPropName, true, Alembic::AbcGeom::kFacevaryingScope, 1, iTimeIndex, md); mRGBParams.push_back(colorProp); } else { Alembic::AbcGeom::OC4fGeomParam colorProp(arbParams, colorSetPropName, true, Alembic::AbcGeom::kFacevaryingScope, 1, iTimeIndex, md); mRGBAParams.push_back(colorProp); } } writeColor(); } } if (mWriteUVSets) { MStringArray uvSetNames; lMesh.getUVSetNames(uvSetNames); unsigned int uvSetNamesLen = uvSetNames.length(); if (uvSetNamesLen > 1) { // Create the uv sets compound prop Alembic::Abc::OCompoundProperty arbParams; if (mPolySchema.valid()) { arbParams = mPolySchema.getArbGeomParams(); } else { arbParams = mSubDSchema.getArbGeomParams(); } MString currentUV = lMesh.currentUVSetName(); for (unsigned int i = 0; i < uvSetNamesLen; ++i) { // Create an array property for each uv set MString uvSetPropName = uvSetNames[i]; // the current UV set gets mapped to the primary UVs if (currentUV == uvSetPropName) { continue; } if (uvSetPropName.length() > 0 && lMesh.numUVs(uvSetPropName) > 0) { mUVparams.push_back(Alembic::AbcGeom::OV2fGeomParam( arbParams, uvSetPropName.asChar(), true, Alembic::AbcGeom::kFacevaryingScope, 1, iTimeIndex)); } } writeUVSets(); } } // write out facesets if(!iArgs.writeFaceSets) return; // get the connected shading engines MObjectArray connSGObjs (getOutConnectedSG(mDagPath)); const unsigned int sgCount = connSGObjs.length(); for (unsigned int i = 0; i < sgCount; ++i) { MObject connSGObj, compObj; connSGObj = connSGObjs[i]; MFnDependencyNode fnDepNode(connSGObj); MString connSgObjName = fnDepNode.name(); // retrive the component MObject status = getSetComponents(mDagPath, connSGObj, gmMap, compObj); if (status != MS::kSuccess) { // for some reason the shading group doesn't represent a face set continue; } // retrieve the face indices MIntArray indices; MFnSingleIndexedComponent compFn; compFn.setObject(compObj); compFn.getElements(indices); const unsigned int numData = indices.length(); // encountered the whole object mapping. skip it. if (numData == 0) continue; std::vector<Alembic::Util::int32_t> faceIndices(numData); for (unsigned int j = 0; j < numData; ++j) { faceIndices[j] = indices[j]; } connSgObjName = util::stripNamespaces(connSgObjName, iArgs.stripNamespace); Alembic::AbcGeom::OFaceSet faceSet; std::string faceSetName(connSgObjName.asChar()); MPlug abcFacesetNamePlug = fnDepNode.findPlug("AbcFacesetName", true); if (!abcFacesetNamePlug.isNull()) { faceSetName = abcFacesetNamePlug.asString().asChar(); } if (mPolySchema.valid()) { if (mPolySchema.hasFaceSet(faceSetName)) { faceSet = mPolySchema.getFaceSet(faceSetName); } else { faceSet = mPolySchema.createFaceSet(faceSetName); } } else { if (mSubDSchema.hasFaceSet(faceSetName)) { faceSet = mSubDSchema.getFaceSet(faceSetName); } else { faceSet = mSubDSchema.createFaceSet(faceSetName); } } Alembic::AbcGeom::OFaceSetSchema::Sample samp; samp.setFaces(Alembic::Abc::Int32ArraySample(faceIndices)); Alembic::AbcGeom::OFaceSetSchema faceSetSchema = faceSet.getSchema(); faceSetSchema.set(samp); faceSetSchema.setFaceExclusivity(Alembic::AbcGeom::kFaceSetExclusive); MFnDependencyNode iNode(connSGObj); Alembic::Abc::OCompoundProperty cp; Alembic::Abc::OCompoundProperty up; if (AttributesWriter::hasAnyAttr(iNode, iArgs)) { cp = faceSetSchema.getArbGeomParams(); up = faceSetSchema.getUserProperties(); } AttributesWriter attrWriter(cp, up, faceSet, iNode, iTimeIndex, iArgs); attrWriter.write(); } }
bool apiSimpleShapeUI::selectVertices( MSelectInfo &selectInfo, MSelectionList &selectionList, MPointArray &worldSpaceSelectPts ) const // // Description: // // Vertex selection. // // Arguments: // // selectInfo - the selection state information // selectionList - the list of selected items to add to // worldSpaceSelectPts - // { bool selected = false; M3dView view = selectInfo.view(); MPoint xformedPoint; MPoint currentPoint; MPoint selectionPoint; double z,previousZ = 0.0; int closestPointVertexIndex = -1; const MDagPath & path = selectInfo.multiPath(); // Create a component that will store the selected vertices // MFnSingleIndexedComponent fnComponent; MObject surfaceComponent = fnComponent.create( MFn::kMeshVertComponent ); int vertexIndex; // if the user did a single mouse click and we find > 1 selection // we will use the alignmentMatrix to find out which is the closest // MMatrix alignmentMatrix; MPoint singlePoint; bool singleSelection = selectInfo.singleSelection(); if( singleSelection ) { alignmentMatrix = selectInfo.getAlignmentMatrix(); } // Get the geometry information // apiSimpleShape* shape = (apiSimpleShape*) surfaceShape(); MVectorArray* geomPtr = shape->getControlPoints(); MVectorArray& geom = *geomPtr; // Loop through all vertices of the mesh and // see if they lie withing the selection area // int numVertices = geom.length(); for ( vertexIndex=0; vertexIndex<numVertices; vertexIndex++ ) { const MVector& point = geom[ vertexIndex ]; // Sets OpenGL's render mode to select and stores // selected items in a pick buffer // view.beginSelect(); glBegin( GL_POINTS ); glVertex3f( (float)point[0], (float)point[1], (float)point[2] ); glEnd(); if ( view.endSelect() > 0 ) // Hit count > 0 { selected = true; if ( singleSelection ) { xformedPoint = currentPoint; xformedPoint.homogenize(); xformedPoint*= alignmentMatrix; z = xformedPoint.z; if ( closestPointVertexIndex < 0 || z > previousZ ) { closestPointVertexIndex = vertexIndex; singlePoint = currentPoint; previousZ = z; } } else { // multiple selection, store all elements // fnComponent.addElement( vertexIndex ); } } } // If single selection, insert the closest point into the array // if ( selected && selectInfo.singleSelection() ) { fnComponent.addElement(closestPointVertexIndex); // need to get world space position for this vertex // selectionPoint = singlePoint; selectionPoint *= path.inclusiveMatrix(); } // Add the selected component to the selection list // if ( selected ) { MSelectionList selectionItem; selectionItem.add( path, surfaceComponent ); MSelectionMask mask( MSelectionMask::kSelectComponentsMask ); selectInfo.addSelection( selectionItem, selectionPoint, selectionList, worldSpaceSelectPts, mask, true ); } return selected; }
MStatus SelectRingContext1::doRelease( MEvent &event ) { // Get the mouse release position event.getPosition( releaseX, releaseY ); // Didn't select a single point if( abs(pressX - releaseX) > 1 || abs(pressY - releaseY) > 1 ) { MGlobal::displayWarning( "Click on a single edge" ); return MS::kFailure; } // Set the selection surface area int halfClickBoxSize = clickBoxSize / 2; pressX -= halfClickBoxSize; pressY -= halfClickBoxSize; releaseX = pressX + clickBoxSize; releaseY = pressY + clickBoxSize; /* // Record previous selection state prevSelMode = MGlobal::selectionMode(); prevCompMask = MGlobal::componentSelectionMask(); */ // Get the current selection MSelectionList curSel; MGlobal::getActiveSelectionList( curSel ); //MGlobal::displayInfo( MString("Dim: ") + start_x + " " + start_y + " " + last_x + " " + last_y ); // Change to object selection mode MGlobal::setSelectionMode( MGlobal::kSelectObjectMode ); MGlobal::setComponentSelectionMask( MSelectionMask( MSelectionMask::kSelectObjectsMask ) ); // Select the object under the selection area MGlobal::selectFromScreen( pressX, pressY, releaseX, releaseY, MGlobal::kReplaceList); MGlobal::executeCommand( "hilite" ); // Change selection mode to mesh edges MGlobal::setSelectionMode( MGlobal::kSelectComponentMode ); MGlobal::setComponentSelectionMask( MSelectionMask( MSelectionMask::kSelectMeshEdges ) ); // Select the edges MGlobal::selectFromScreen( pressX, pressY, releaseX, releaseY, MGlobal::kReplaceList ); // Get the list of selected edges MSelectionList origEdgesSel; MGlobal::getActiveSelectionList( origEdgesSel ); MSelectionList newEdgesSel; MDagPath dagPath; MObject component; // Only use the first edge in the selection MItSelectionList selIter( origEdgesSel, MFn::kMeshEdgeComponent ); if( !selIter.isDone() ) { selIter.getDagPath( dagPath, component ); MIntArray faces; MItMeshEdge edgeIter( dagPath, component ); MIntArray edgesVisited, facesVisited; int edgeIndex, faceIndex; int prevIndex; unsigned int i; bool finished = false; while( !finished ) { edgeIndex = edgeIter.index(); edgesVisited.append( edgeIndex ); // Create an edge component the current edge MFnSingleIndexedComponent indexedCompFn; MObject newComponent = indexedCompFn.create( MFn::kMeshEdgeComponent ); indexedCompFn.addElement( edgeIndex ); newEdgesSel.add( dagPath, newComponent ); //MGlobal::displayInfo( MString("ADDING: ") + edgeIter.index() ); edgeIter.getConnectedFaces( faces ); faceIndex = faces[0]; if( faces.length() > 1 ) { // Select the face that hasn't already been visited for( i=0; i < facesVisited.length(); i++ ) { if( faceIndex == facesVisited[i] ) { faceIndex = faces[1]; break; } } } //MGlobal::displayInfo( MString("FACE: ") + faceIndex ); facesVisited.append( faceIndex ); MItMeshPolygon polyIter( dagPath ); polyIter.setIndex( faceIndex, prevIndex ); //MGlobal::displayInfo( MString( "faces: " ) + faces[0] + " " + faces[1] ); MIntArray edges; polyIter.getEdges( edges ); // Determine the face-relative index of the current // edge unsigned int edgeFaceIndex = 0; for( i=0; i < edges.length(); i++ ) { if( edges[i] == edgeIter.index() ) { edgeFaceIndex = i; break; } } // Determine the edge that is opposite the current edge edgeIndex = edges[ (edgeFaceIndex + (edges.length() / 2) ) % edges.length() ]; //int index = edgeIter.index(); //MGlobal::displayInfo( MString( "sel edge index: " ) + index + " next edge: " + edgeIndex ); // Set the current edge to the opposite edge edgeIter.setIndex( edgeIndex, prevIndex ); // Determine if the edge has already been visited for( i=0; i < edgesVisited.length(); i++ ) { if( edgeIndex == edgesVisited[i] ) { finished = true; break; } } } } // Set the active selection to the one previous to edge loop selection MGlobal::setActiveSelectionList( curSel, MGlobal::kReplaceList); // Update this selection based on the list adjustment setting MGlobal::selectCommand( newEdgesSel, listAdjust ); return MS::kSuccess; }
void NifMeshExporterSkyrim::ExportMesh( MObject dagNode ) { //out << "NifTranslator::ExportMesh {"; ComplexShape cs; MStatus stat; MObject mesh; //Find Mesh child of given transform object MFnDagNode nodeFn(dagNode); cs.SetName(this->translatorUtils->MakeNifName(nodeFn.name())); for (int i = 0; i != nodeFn.childCount(); ++i) { // get a handle to the child if (nodeFn.child(i).hasFn(MFn::kMesh)) { MFnMesh tempFn(nodeFn.child(i)); //No history items if (!tempFn.isIntermediateObject()) { //out << "Found a mesh child." << endl; mesh = nodeFn.child(i); break; } } } MFnMesh visibleMeshFn(mesh, &stat); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to create visibleMeshFn."); } //out << visibleMeshFn.name().asChar() << ") {" << endl; MFnMesh meshFn; MObject dataObj; MPlugArray inMeshPlugArray; MPlug childPlug; MPlug geomPlug; MPlug inputPlug; // this will hold the returned vertex positions MPointArray vts; //For now always use the visible mesh meshFn.setObject(mesh); //out << "Use the function set to get the points" << endl; // use the function set to get the points stat = meshFn.getPoints(vts); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to get points."); } //Maya won't store any information about objects with no vertices. Just skip it. if (vts.length() == 0) { MGlobal::displayWarning("An object in this scene has no vertices. Nothing will be exported."); return; } vector<WeightedVertex> nif_vts(vts.length()); for (int i = 0; i != vts.length(); ++i) { nif_vts[i].position.x = float(vts[i].x); nif_vts[i].position.y = float(vts[i].y); nif_vts[i].position.z = float(vts[i].z); } //Set vertex info later since it includes skin weights //cs.SetVertices( nif_vts ); //out << "Use the function set to get the colors" << endl; MColorArray myColors; meshFn.getFaceVertexColors(myColors); //out << "Prepare NIF color vector" << endl; vector<Color4> niColors(myColors.length()); for (unsigned int i = 0; i < myColors.length(); ++i) { niColors[i] = Color4(myColors[i].r, myColors[i].g, myColors[i].b, myColors[i].a); } cs.SetColors(niColors); // this will hold the returned vertex positions MFloatVectorArray nmls; //out << "Use the function set to get the normals" << endl; // use the function set to get the normals stat = meshFn.getNormals(nmls, MSpace::kTransform); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to get normals"); } //out << "Prepare NIF normal vector" << endl; vector<Vector3> nif_nmls(nmls.length()); for (int i = 0; i != nmls.length(); ++i) { nif_nmls[i].x = float(nmls[i].x); nif_nmls[i].y = float(nmls[i].y); nif_nmls[i].z = float(nmls[i].z); } cs.SetNormals(nif_nmls); //out << "Use the function set to get the UV set names" << endl; MStringArray uvSetNames; MString baseUVSet; MFloatArray myUCoords; MFloatArray myVCoords; bool has_uvs = false; // get the names of the uv sets on the mesh meshFn.getUVSetNames(uvSetNames); vector<TexCoordSet> nif_uvs; //Record assotiation between name and uv set index for later map<string, int> uvSetNums; int set_num = 0; for (unsigned int i = 0; i < uvSetNames.length(); ++i) { if (meshFn.numUVs(uvSetNames[i]) > 0) { TexType tt; string set_name = uvSetNames[i].asChar(); if (set_name == "base" || set_name == "map1") { tt = BASE_MAP; } else if (set_name == "dark") { tt = DARK_MAP; } else if (set_name == "detail") { tt = DETAIL_MAP; } else if (set_name == "gloss") { tt = GLOSS_MAP; } else if (set_name == "glow") { tt = GLOW_MAP; } else if (set_name == "bump") { tt = BUMP_MAP; } else if (set_name == "decal0") { tt = DECAL_0_MAP; } else if (set_name == "decal1") { tt = DECAL_1_MAP; } else { tt = BASE_MAP; } //Record the assotiation uvSetNums[set_name] = set_num; //Get the UVs meshFn.getUVs(myUCoords, myVCoords, &uvSetNames[i]); //Make sure this set actually has some UVs in it. Maya sometimes returns empty UV sets. if (myUCoords.length() == 0) { continue; } //Store the data TexCoordSet tcs; tcs.texType = tt; tcs.texCoords.resize(myUCoords.length()); for (unsigned int j = 0; j < myUCoords.length(); ++j) { tcs.texCoords[j].u = myUCoords[j]; //Flip the V coords tcs.texCoords[j].v = 1.0f - myVCoords[j]; } nif_uvs.push_back(tcs); baseUVSet = uvSetNames[i]; has_uvs = true; set_num++; } } cs.SetTexCoordSets(nif_uvs); // this will hold references to the shaders used on the meshes MObjectArray Shaders; // this is used to hold indices to the materials returned in the object array MIntArray FaceIndices; //out << "Get the connected shaders" << endl; // get the shaders used by the i'th mesh instance // Assume this is not instanced for now // TODO support instancing properly stat = visibleMeshFn.getConnectedShaders(0, Shaders, FaceIndices); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to get connected shader list."); } vector<ComplexFace> nif_faces; //Add shaders to propGroup array vector< vector<NiPropertyRef> > propGroups; for (unsigned int shader_num = 0; shader_num < Shaders.length(); ++shader_num) { //Maya sometimes lists shaders that are not actually attached to any face. Disregard them. bool shader_is_used = false; for (size_t f = 0; f < FaceIndices.length(); ++f) { if (FaceIndices[f] == shader_num) { shader_is_used = true; break; } } if (shader_is_used == false) { //Shader isn't actually used, so continue to the next one. continue; } //out << "Found attached shader: "; //Attach all properties previously associated with this shader to //this NiTriShape MFnDependencyNode fnDep(Shaders[shader_num]); //Find the shader that this shading group connects to MPlug p = fnDep.findPlug("surfaceShader"); MPlugArray plugs; p.connectedTo(plugs, true, false); for (unsigned int i = 0; i < plugs.length(); ++i) { if (plugs[i].node().hasFn(MFn::kLambert)) { fnDep.setObject(plugs[i].node()); break; } } //out << fnDep.name().asChar() << endl; vector<NiPropertyRef> niProps = this->translatorData->shaders[fnDep.name().asChar()]; propGroups.push_back(niProps); } cs.SetPropGroups(propGroups); //out << "Export vertex and normal data" << endl; // attach an iterator to the mesh MItMeshPolygon itPoly(mesh, &stat); if (stat != MS::kSuccess) { throw runtime_error("Failed to create polygon iterator."); } // Create a list of faces with vertex IDs, and duplicate normals so they have the same ID for (; !itPoly.isDone(); itPoly.next()) { int poly_vert_count = itPoly.polygonVertexCount(&stat); if (stat != MS::kSuccess) { throw runtime_error("Failed to get vertex count."); } //Ignore polygons with less than 3 vertices if (poly_vert_count < 3) { continue; } ComplexFace cf; //Assume all faces use material 0 for now cf.propGroupIndex = 0; for (int i = 0; i < poly_vert_count; ++i) { ComplexPoint cp; cp.vertexIndex = itPoly.vertexIndex(i); cp.normalIndex = itPoly.normalIndex(i); if (niColors.size() > 0) { int color_index; stat = meshFn.getFaceVertexColorIndex(itPoly.index(), i, color_index); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to get vertex color."); } cp.colorIndex = color_index; } //Get the UV set names used by this particular vertex MStringArray vertUvSetNames; itPoly.getUVSetNames(vertUvSetNames); for (unsigned int j = 0; j < vertUvSetNames.length(); ++j) { TexCoordIndex tci; tci.texCoordSetIndex = uvSetNums[vertUvSetNames[j].asChar()]; int uv_index; itPoly.getUVIndex(i, uv_index, &vertUvSetNames[j]); tci.texCoordIndex = uv_index; cp.texCoordIndices.push_back(tci); } cf.points.push_back(cp); } nif_faces.push_back(cf); } //Set shader/face association if (nif_faces.size() != FaceIndices.length()) { throw runtime_error("Num faces found do not match num faces reported."); } for (unsigned int face_index = 0; face_index < nif_faces.size(); ++face_index) { nif_faces[face_index].propGroupIndex = FaceIndices[face_index]; } cs.SetFaces(nif_faces); //--Skin Processing--// //Look up any skin clusters if (this->translatorData->meshClusters.find(visibleMeshFn.fullPathName().asChar()) != this->translatorData->meshClusters.end()) { const vector<MObject> & clusters = this->translatorData->meshClusters[visibleMeshFn.fullPathName().asChar()]; if (clusters.size() > 1) { throw runtime_error("Objects with multiple skin clusters affecting them are not currently supported. Try deleting the history and re-binding them."); } vector<MObject>::const_iterator cluster = clusters.begin(); if (cluster->isNull() != true) { MFnSkinCluster clusterFn(*cluster); //out << "Processing skin..." << endl; //Get path to visible mesh MDagPath meshPath; visibleMeshFn.getPath(meshPath); //out << "Getting a list of all verticies in this mesh" << endl; //Get a list of all vertices in this mesh MFnSingleIndexedComponent compFn; MObject vertices = compFn.create(MFn::kMeshVertComponent); MItGeometry gIt(meshPath); MIntArray vertex_indices(gIt.count()); for (int vert_index = 0; vert_index < gIt.count(); ++vert_index) { vertex_indices[vert_index] = vert_index; } compFn.addElements(vertex_indices); //out << "Getting Influences" << endl; //Get influences MDagPathArray myBones; clusterFn.influenceObjects(myBones, &stat); //out << "Creating a list of NiNodeRefs of influences." << endl; //Create list of NiNodeRefs of influences vector<NiNodeRef> niBones(myBones.length()); for (unsigned int bone_index = 0; bone_index < niBones.size(); ++bone_index) { const char* boneName = myBones[bone_index].fullPathName().asChar(); if (this->translatorData->nodes.find(myBones[bone_index].fullPathName().asChar()) == this->translatorData->nodes.end()) { //There is a problem; one of the joints was not exported. Abort. throw runtime_error("One of the joints necessary to export a bound skin was not exported."); } niBones[bone_index] = this->translatorData->nodes[myBones[bone_index].fullPathName().asChar()]; } //out << "Getting weights from Maya" << endl; //Get weights from Maya MDoubleArray myWeights; unsigned int bone_count = myBones.length(); stat = clusterFn.getWeights(meshPath, vertices, myWeights, bone_count); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to get vertex weights."); } //out << "Setting skin influence list in ComplexShape" << endl; //Set skin information in ComplexShape cs.SetSkinInfluences(niBones); //out << "Adding weights to ComplexShape vertices" << endl; //out << "Number of weights: " << myWeights.length() << endl; //out << "Number of bones: " << myBones.length() << endl; //out << "Number of Maya vertices: " << gIt.count() << endl; //out << "Number of NIF vertices: " << int(nif_vts.size()) << endl; unsigned int weight_index = 0; SkinInfluence sk; for (unsigned int vert_index = 0; vert_index < nif_vts.size(); ++vert_index) { for (unsigned int bone_index = 0; bone_index < myBones.length(); ++bone_index) { //out << "vert_index: " << vert_index << " bone_index: " << bone_index << " weight_index: " << weight_index << endl; // Only bother with weights that are significant if (myWeights[weight_index] > 0.0f) { sk.influenceIndex = bone_index; sk.weight = float(myWeights[weight_index]); nif_vts[vert_index].weights.push_back(sk); } ++weight_index; } } } MPlugArray connected_dismember_plugs; MObjectArray dismember_nodes; meshFn.findPlug("message").connectedTo(connected_dismember_plugs, false, true); bool has_valid_dismemember_partitions = true; int faces_count = cs.GetFaces().size(); int current_face_index; vector<BodyPartList> body_parts_list; vector<uint> dismember_faces(faces_count, 0); for (int x = 0; x < connected_dismember_plugs.length(); x++) { MFnDependencyNode dependency_node(connected_dismember_plugs[x].node()); if (dependency_node.typeName() == "nifDismemberPartition") { dismember_nodes.append(dependency_node.object()); } } if (dismember_nodes.length() == 0) { has_valid_dismemember_partitions = false; } else { int blind_data_id; int blind_data_value; MStatus status; MPlug target_faces_plug; MItMeshPolygon it_polygons(meshFn.object()); MString mel_command; MStringArray current_body_parts_flags; MFnDependencyNode current_dismember_node; MFnDependencyNode current_blind_data_node; //Naive sort here, there is no reason and is extremely undesirable and not recommended to have more //than 10-20 dismember partitions out of many reasons, so it's okay here //as it makes the code easier to understand vector<int> dismember_nodes_id(dismember_nodes.length(), -1); for (int x = 0; x < dismember_nodes.length(); x++) { current_dismember_node.setObject(dismember_nodes[x]); connected_dismember_plugs.clear(); current_dismember_node.findPlug("targetFaces").connectedTo(connected_dismember_plugs, true, false); if (connected_dismember_plugs.length() == 0) { has_valid_dismemember_partitions = false; break; } current_blind_data_node.setObject(connected_dismember_plugs[0].node()); dismember_nodes_id[x] = current_blind_data_node.findPlug("typeId").asInt(); } for (int x = 0; x < dismember_nodes.length() - 1; x++) { for (int y = x + 1; y < dismember_nodes.length(); y++) { if (dismember_nodes_id[x] > dismember_nodes_id[y]) { MObject aux = dismember_nodes[x]; blind_data_id = dismember_nodes_id[x]; dismember_nodes[x] = dismember_nodes[y]; dismember_nodes_id[x] = dismember_nodes_id[y]; dismember_nodes[y] = aux; dismember_nodes_id[y] = blind_data_id; } } } for (int x = 0; x < dismember_nodes.length(); x++) { current_dismember_node.setObject(dismember_nodes[x]); target_faces_plug = current_dismember_node.findPlug("targetFaces"); connected_dismember_plugs.clear(); target_faces_plug.connectedTo(connected_dismember_plugs, true, false); if (connected_dismember_plugs.length() > 0) { current_blind_data_node.setObject(connected_dismember_plugs[0].node()); current_face_index = 0; blind_data_id = current_blind_data_node.findPlug("typeId").asInt(); for (it_polygons.reset(); !it_polygons.isDone(); it_polygons.next()) { if (it_polygons.polygonVertexCount() >= 3) { status = meshFn.getIntBlindData(it_polygons.index(), MFn::Type::kMeshPolygonComponent, blind_data_id, "dismemberValue", blind_data_value); if (status == MStatus::kSuccess && blind_data_value == 1 && meshFn.hasBlindDataComponentId(it_polygons.index(), MFn::Type::kMeshPolygonComponent, blind_data_id)) { dismember_faces[current_face_index] = x; } current_face_index++; } } } else { has_valid_dismemember_partitions = false; break; } mel_command = "getAttr "; mel_command += current_dismember_node.name(); mel_command += ".bodyPartsFlags"; status = MGlobal::executeCommand(mel_command, current_body_parts_flags); BSDismemberBodyPartType body_part_type = NifDismemberPartition::stringArrayToBodyPartType(current_body_parts_flags); current_body_parts_flags.clear(); mel_command = "getAttr "; mel_command += current_dismember_node.name(); mel_command += ".partsFlags"; status = MGlobal::executeCommand(mel_command, current_body_parts_flags); BSPartFlag part_type = NifDismemberPartition::stringArrayToPart(current_body_parts_flags); current_body_parts_flags.clear(); BodyPartList body_part; body_part.bodyPart = body_part_type; body_part.partFlag = part_type; body_parts_list.push_back(body_part); } } if (has_valid_dismemember_partitions == false) { MGlobal::displayWarning("No proper dismember partitions, generating default ones for " + meshFn.name()); for (int x = 0; x < dismember_faces.size(); x++) { dismember_faces[x] = 0; } BodyPartList body_part; body_part.bodyPart = (BSDismemberBodyPartType)0; body_part.partFlag = (BSPartFlag)(PF_EDITOR_VISIBLE | PF_START_NET_BONESET); body_parts_list.clear(); body_parts_list.push_back(body_part); } cs.SetDismemberPartitionsBodyParts(body_parts_list); cs.SetDismemberPartitionsFaces(dismember_faces); } //out << "Setting vertex info" << endl; //Set vertex info now that any skins have been processed cs.SetVertices(nif_vts); //ComplexShape is now complete, so split it //Get parent NiNodeRef parNode = this->translatorUtils->GetDAGParent(dagNode); Matrix44 transform = Matrix44::IDENTITY; vector<NiNodeRef> influences = cs.GetSkinInfluences(); if (influences.size() > 0) { //This is a skin, so we use the common ancestor of all influences //as the parent vector<NiAVObjectRef> objects; for (size_t i = 0; i < influences.size(); ++i) { objects.push_back(StaticCast<NiAVObject>(influences[i])); } //Get world transform of existing parent Matrix44 oldParWorld = parNode->GetWorldTransform(); //Set new parent node parNode = FindCommonAncestor(objects); transform = oldParWorld * parNode->GetWorldTransform().Inverse(); } //Get transform using temporary NiAVObject NiAVObjectRef tempAV = new NiAVObject; this->nodeExporter->ExportAV(tempAV, dagNode); NiAVObjectRef avObj; if (this->translatorOptions->exportTangentSpace == "falloutskyrimtangentspace") { //out << "Split ComplexShape from " << meshFn.name().asChar() << endl; avObj = cs.Split(parNode, tempAV->GetLocalTransform() * transform, this->translatorOptions->exportBonesPerSkinPartition, this->translatorOptions->exportAsTriStrips, true, this->translatorOptions->exportMinimumVertexWeight, 16); } else { avObj = cs.Split(parNode, tempAV->GetLocalTransform() * transform, this->translatorOptions->exportBonesPerSkinPartition, this->translatorOptions->exportAsTriStrips, false, this->translatorOptions->exportMinimumVertexWeight); } //out << "Get the NiAVObject portion of the root of the split" <<endl; //Get the NiAVObject portion of the root of the split avObj->SetName(tempAV->GetName()); avObj->SetVisibility(tempAV->GetVisibility()); avObj->SetFlags(tempAV->GetFlags()); //If polygon mesh is hidden, hide tri_shape MPlug vis = visibleMeshFn.findPlug(MString("visibility")); bool visibility; vis.getValue(visibility); NiNodeRef splitRoot = DynamicCast<NiNode>(avObj); if (splitRoot != NULL) { //Root is a NiNode with NiTriBasedGeom children. vector<NiAVObjectRef> children = splitRoot->GetChildren(); for (unsigned c = 0; c < children.size(); ++c) { //Set the default collision propogation flag to "use triangles" children[c]->SetFlags(2); // Make the mesh invisible if necessary if (visibility == false) { children[c]->SetVisibility(false); } } } else { //Root must be a NiTriBasedGeom. Make it invisible if necessary if (visibility == false) { avObj->SetVisibility(false); } } }
bool SceneShapeUI::select( MSelectInfo &selectInfo, MSelectionList &selectionList, MPointArray &worldSpaceSelectPts ) const { MStatus s; // early out if we're not selectable. we always allow components to be selected if we're highlighted, // but we don't allow ourselves to be selected as a whole unless meshes are in the selection mask. // it's not ideal that we act like a mesh, but it's at least consistent with the drawing mask we use. if( selectInfo.displayStatus() != M3dView::kHilite ) { MSelectionMask meshMask( MSelectionMask::kSelectMeshes ); // Apparently selectInfo.selectable() still returns true when meshes are not // displayed by the M3dView, so we are also testing the objectDisplay status. // This was last confirmed in Maya 2014, and is presumably a Maya bug. if( !selectInfo.selectable( meshMask ) || !selectInfo.objectDisplayStatus( M3dView::kDisplayMeshes ) ) { return false; } } // early out if we have no scene to draw SceneShape *sceneShape = static_cast<SceneShape *>( surfaceShape() ); if( !sceneShape->getSceneInterface() ) { return false; } IECoreGL::ConstScenePtr scene = sceneShape->glScene(); if( !scene ) { return false; } // we want to perform the selection using an IECoreGL::Selector, so we // can avoid the performance penalty associated with using GL_SELECT mode. // that means we don't really want to call view.beginSelect(), but we have to // call it just to get the projection matrix for our own selection, because as far // as I can tell, there is no other way of getting it reliably. M3dView view = selectInfo.view(); view.beginSelect(); Imath::M44d projectionMatrix; glGetDoublev( GL_PROJECTION_MATRIX, projectionMatrix.getValue() ); view.endSelect(); view.beginGL(); glMatrixMode( GL_PROJECTION ); glLoadMatrixd( projectionMatrix.getValue() ); IECoreGL::Selector::Mode selectionMode = IECoreGL::Selector::IDRender; if( selectInfo.displayStatus() == M3dView::kHilite && !selectInfo.singleSelection() ) { selectionMode = IECoreGL::Selector::OcclusionQuery; } std::vector<IECoreGL::HitRecord> hits; { IECoreGL::Selector selector( Imath::Box2f( Imath::V2f( 0 ), Imath::V2f( 1 ) ), selectionMode, hits ); IECoreGL::State::bindBaseState(); selector.baseState()->bind(); scene->render( selector.baseState() ); if( selectInfo.displayStatus() != M3dView::kHilite ) { // We're not in component selection mode. We'd like to be able to select the scene shape // using the bounding box so we draw it too but only if it is visible MPlug pDrawBound( sceneShape->thisMObject(), SceneShape::aDrawRootBound ); bool drawBound; pDrawBound.getValue( drawBound ); if( drawBound ) { IECoreGL::BoxPrimitive::renderWireframe( IECore::convert<Imath::Box3f>( sceneShape->boundingBox() ) ); } } } view.endGL(); if( hits.empty() ) { return false; } // iterate over the hits, converting them into components and also finding // the closest one. MIntArray componentIndices; float depthMin = std::numeric_limits<float>::max(); int depthMinIndex = -1; for( unsigned int i=0, e = hits.size(); i < e; i++ ) { if( hits[i].depthMin < depthMin ) { depthMin = hits[i].depthMin; depthMinIndex = componentIndices.length(); } int index = sceneShape->selectionIndex( IECoreGL::NameStateComponent::nameFromGLName( hits[i].name ) ); componentIndices.append( index ); } assert( depthMinIndex >= 0 ); // figure out the world space location of the closest hit MDagPath camera; view.getCamera( camera ); MPoint worldIntersectionPoint; selectionRayToWorldSpacePoint( camera, selectInfo, depthMin, worldIntersectionPoint ); // turn the processed hits into appropriate changes to the current selection if( selectInfo.displayStatus() == M3dView::kHilite ) { // selecting components MFnSingleIndexedComponent fnComponent; MObject component = fnComponent.create( MFn::kMeshPolygonComponent, &s ); assert( s ); if( selectInfo.singleSelection() ) { fnComponent.addElement( componentIndices[depthMinIndex] ); } else { fnComponent.addElements( componentIndices ); } MSelectionList items; items.add( selectInfo.multiPath(), component ); MDagPath path = selectInfo.multiPath(); selectInfo.addSelection( items, worldIntersectionPoint, selectionList, worldSpaceSelectPts, MSelectionMask::kSelectMeshFaces, true ); } else { // Check if we should be able to select that object MPlug pObjectOnly( sceneShape->thisMObject(), SceneShape::aObjectOnly ); bool objectOnly; pObjectOnly.getValue( objectOnly ); if( objectOnly && !sceneShape->getSceneInterface()->hasObject() ) { return true; } // selecting objects MSelectionList item; item.add( selectInfo.selectPath() ); selectInfo.addSelection( item, worldIntersectionPoint, selectionList, worldSpaceSelectPts, MSelectionMask::kSelectMeshes, false ); } return true; }
CacheMeshSampler::AttributeSet::AttributeSet( MFnMesh& mesh, const bool needUVs, const bool useBaseTessellation ) :fNumWires(0), fNumTriangles(0), fNumVerts(0) { // Refresh the internal shape, otherwise topo changes make mesh.numPolygons() crash. // Note that buildShaderAssignmentGroups() also call mesh.numPolygons(). mesh.syncObject(); MDagPath dagPath; mesh.getPath(dagPath); // build a geometry request and add requirements to it. MHWRender::MGeometryRequirements geomRequirements; // Build descriptors to request the positions, normals and UVs MVertexBufferDescriptor posDesc("", MGeometry::kPosition, MGeometry::kFloat, 3); MVertexBufferDescriptor normalDesc("", MGeometry::kNormal, MGeometry::kFloat, 3); MVertexBufferDescriptor uvDesc(mesh.currentUVSetName(), MGeometry::kTexture, MGeometry::kFloat, 2); // add the descriptors to the geometry requirements geomRequirements.addVertexRequirement(posDesc); geomRequirements.addVertexRequirement(normalDesc); if (needUVs) geomRequirements.addVertexRequirement(uvDesc); MString noName; // we do not need custom named index buffers here. // create a component to include all elements. MFnSingleIndexedComponent comp; MObject compObj = comp.create(MFn::kMeshPolygonComponent); comp.setCompleteData(mesh.numPolygons()); // create edge component MFnSingleIndexedComponent edgeComp; MObject edgeCompObj = edgeComp.create(MFn::kMeshEdgeComponent); edgeComp.setCompleteData(mesh.numEdges()); // Add the edge line index buffer to the requirements MIndexBufferDescriptor edgeDesc(MIndexBufferDescriptor::kEdgeLine, noName, MGeometry::kLines, 2, edgeCompObj); geomRequirements.addIndexingRequirement(edgeDesc); // add a triangle buffer to the requirements MIndexBufferDescriptor triangleDesc(MIndexBufferDescriptor::kTriangle, noName, MGeometry::kTriangles, 3, compObj); geomRequirements.addIndexingRequirement(triangleDesc); typedef IndexBuffer::index_t index_t; // We ignore the Smooth Preview option on the mesh shape node when // using base tessellation. int extractorOptions = MHWRender::kPolyGeom_Normal; if (useBaseTessellation) { extractorOptions |= MHWRender::kPolyGeom_BaseMesh; } // create an extractor to get the geometry MStatus status; MHWRender::MGeometryExtractor extractor(geomRequirements,dagPath, extractorOptions, &status); if (MS::kFailure==status) return; // get the number of vertices from the extractor unsigned int numVertices = extractor.vertexCount(); // get the number of primitives (triangles, lines, etc.) unsigned int numWires = extractor.primitiveCount(edgeDesc); // create the arrays that the generator will fill boost::shared_array<float> vertices(new float[numVertices*posDesc.stride()]); boost::shared_array<float> normals(new float[numVertices*normalDesc.stride()]); boost::shared_array<float> uvs(new float[numVertices*uvDesc.stride()]); unsigned int minBufferSize = extractor.minimumBufferSize(numWires, edgeDesc.primitive()); boost::shared_array<index_t> wireframeIdx(new index_t[minBufferSize]); // populate the index buffer for the edges if (MS::kFailure==extractor.populateIndexBuffer(wireframeIdx.get(), numWires, edgeDesc)) return; // populate the vertex buffers you are interested in. (pos, normal, and uv) if (MS::kFailure==extractor.populateVertexBuffer(vertices.get(), numVertices, posDesc)) return; if (MS::kFailure==extractor.populateVertexBuffer(normals.get(), numVertices, normalDesc)) return; if (needUVs && MS::kFailure==extractor.populateVertexBuffer(uvs.get(), numVertices, uvDesc)) return; // populate the index buffers for all the triangle components { std::vector<boost::shared_ptr<Array<index_t> > > trgIdxGrps; // get the index buffer count from the extractor unsigned int numTriangles = extractor.primitiveCount(triangleDesc); minBufferSize = extractor.minimumBufferSize(numTriangles, triangleDesc.primitive()); boost::shared_array<index_t> triangleIdx(new index_t[minBufferSize]); if (numTriangles != 0) { if (MS::kFailure==extractor.populateIndexBuffer(triangleIdx.get(), numTriangles, triangleDesc)) return; fNumTriangles += (size_t)numTriangles; } trgIdxGrps.push_back(SharedArray<index_t>::create( triangleIdx, 3 * numTriangles)); for(size_t i=0, offset=0; i<trgIdxGrps.size(); ++i) { fTriangleVertIndices.push_back(IndexBuffer::create( trgIdxGrps[0], offset, offset + trgIdxGrps[i]->size())); offset += trgIdxGrps[i]->size(); } } fNumWires = (size_t)numWires; fNumVerts = (size_t)numVertices; fWireVertIndices = IndexBuffer::create( SharedArray<index_t>::create( wireframeIdx, 2 * fNumWires)); fPositions = VertexBuffer::createPositions( SharedArray<float>::create( vertices, 3 * fNumVerts)); fNormals = VertexBuffer::createNormals( SharedArray<float>::create( normals, 3 * fNumVerts)); if (needUVs) { fUVs = VertexBuffer::createUVs( SharedArray<float>::create(uvs, 2 * fNumVerts)); } fBoundingBox = mesh.boundingBox(); // Check visibility fVisibility = ShapeVisibilityChecker(mesh.object()).isVisible(); }